summaryrefslogtreecommitdiff
path: root/subversion/bindings/javahl/native/jniwrapper/jni_string.hpp
blob: 7b874d0fdddefe7d45d740378d64e879c4cf5c5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/**
 * @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_STRING_HPP
#define SVN_JAVAHL_JNIWRAPPER_STRING_HPP

#include <cstring>
#include <string>

#include <apr_pools.h>

#include "jni_object.hpp"

namespace Java {

/**
 * Object wrapper for @c java.lang.String.
 *
 * The associated JNI class reference is stored for the lifetime of
 * the JVM in the global class cache.
 *
 * @since New in 1.9.
 */
class String
{
public:
  /**
   * Constructs a wrapper around an existing string @a str.
   */
  explicit String(Env env, jstring str)
    : m_env(env),
      m_jthis(str)
    {}

  /**
   * Constructs a new string and wrapper from @a text.
   */
  explicit String(Env env, const char* text)
    : m_env(env),
      m_jthis(env.NewStringUTF(text))
    {}

  /**
   * Constructs a new string and wrapper from @a text.
   */
  explicit String(Env env, const std::string& text)
    : m_env(env),
      m_jthis(env.NewStringUTF(text.c_str()))
    {}

  /**
   * Returns the wrapped JNI object reference.
   */
  jstring get() const
    {
      return m_jthis;
    }

  /**
   * Returns the wrapped enviromnment reference.
   */
  Env get_env() const
    {
      return m_env;
    }

  /**
   * Returns the number of Unicode characters in the string.
   */
  jsize length() const
    {
      return m_env.GetStringLength(get());
    }

  /**
   * Returns the length of the modified UTF-8 representation of the
   * string.
   */
  jsize utf8_length() const
    {
      return m_env.GetStringUTFLength(get());
    }

  /**
   * Copies the contents of the modified UTF-8 representation of the
   * string into @a pool.
   */
  const char* strdup(apr_pool_t* pool) const;

  /**
   * Accessor class for the contents of the string.
   *
   * Objects of this class should be created within the scope where
   * the raw C string is required. They will create an immutable
   * modified UTF-8 representation of the string contents. The data
   * will be released by the destructor.
   */
  class Contents
  {
  public:
    /**
     * Constructs an immutable string contents accessor.
     */
    explicit Contents(const String& str)
      : m_str(str),
        m_text(!str.get() ? NULL
               : str.m_env.GetStringUTFChars(str.get(), NULL)),
        m_length(m_text ? jsize(::std::strlen(m_text)) : 0)
      {}

    /**
     * Releases the string contents, possibly committing changes to the JVM.
     */
    ~Contents()
      {
        if (m_text)
          m_str.m_env.ReleaseStringUTFChars(m_str.get(), NULL);
      }

    /**
     * Returns the C representation of the string contents.
     */
    const char* c_str() const
      {
        return m_text;
      }

    /**
     * Returns the length of the C representation of the string.
     */
    jsize utf8_length() const
      {
        return m_length;
      }

  protected:
    const String& m_str;
    const char* m_text;
    jsize m_length;
  };

  /**
   * Accessor class for the contents of the string.
   *
   * Behaves like the #Contents class, but the representation is
   * considered mutable and can be assigned a new value, which will be
   * subsequently committed to the JVM.
   */
  class MutableContents : protected Contents
  {
  public:
    /**
     * Constructs a mutable string contents accessor.
     */
    explicit MutableContents(String& str)
      : Contents(str),
        m_new_text(NULL)
      {}

    /**
     * Releases the string contents, possibly committing changes to the JVM.
     */
    ~MutableContents()
      {
        if (m_new_text)
          {
            // Prevent double-release by the Contents destructor.
            m_text = NULL;
            m_str.m_env.ReleaseStringUTFChars(m_str.get(), m_new_text);
          }
      }

    /**
     * Returns the C representation of the string contents.
     */
    const char* c_str() const
      {
        if (m_new_text)
          return m_new_text;
        return Contents::c_str();
      }

    /**
     * Returns the length of the C representation of the string.
     */
    jsize utf8_length() const
      {
        return Contents::utf8_length();
      }

    /**
     * Sets a new value for the string, to be committed to the JVM
     * when the accessor object is destroyed.
     * @throw std::invalid_argument if the @a new_text is @c null
     * @throw std::logic_error if this is a @c null or immutable string
     */
    void set_value(const char* new_text);

  private:
    const char* m_new_text;
  };

private:
  const Env m_env;
  const jstring m_jthis;

  /**
   * This object's implementation details.
   */
  class ClassImpl : public Object::ClassImpl
  {
    friend class ClassCacheImpl;

  protected:
    explicit ClassImpl(Env env, jclass cls)
      : Object::ClassImpl(env, cls)
      {}

  public:
    virtual ~ClassImpl();
  };

  friend class Contents;
  friend class MutableContents;
  friend class ClassCacheImpl;
  static const char* const m_class_name;
};

} // namespace Java

#endif // SVN_JAVAHL_JNIWRAPPER_STRING_HPP