BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdljsn_stringutil.h
Go to the documentation of this file.
1/// @file bdljsn_stringutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdljsn_stringutil.h -*-C++-*-
8#ifndef INCLUDED_BDLJSN_STRINGUTIL
9#define INCLUDED_BDLJSN_STRINGUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdljsn_stringutil bdljsn_stringutil
15/// @brief Provide a utility functions for JSON strings.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdljsn
19/// @{
20/// @addtogroup bdljsn_stringutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdljsn_stringutil-purpose"> Purpose</a>
25/// * <a href="#bdljsn_stringutil-classes"> Classes </a>
26/// * <a href="#bdljsn_stringutil-description"> Description </a>
27/// * <a href="#bdljsn_stringutil-json-strings"> JSON Strings </a>
28/// * <a href="#bdljsn_stringutil-guarantees-arbitrary-utf-8-to-json-string"> Guarantees: Arbitrary UTF-8 to JSON String </a>
29/// * <a href="#bdljsn_stringutil-strictness"> Strictness </a>
30/// * <a href="#bdljsn_stringutil-example-variance"> Example Variance </a>
31/// * <a href="#bdljsn_stringutil-usage"> Usage </a>
32/// * <a href="#bdljsn_stringutil-example-1-encoding-and-decoding-a-json-string"> Example 1: Encoding and Decoding a JSON String </a>
33///
34/// # Purpose {#bdljsn_stringutil-purpose}
35/// Provide a utility functions for JSON strings.
36///
37/// # Classes {#bdljsn_stringutil-classes}
38///
39/// - bdljsn::StringUtil: namespace for utility functions on JSON strings
40///
41/// # Description {#bdljsn_stringutil-description}
42/// This component defines a utility `struct`,
43/// `bdljsn::StringUtil`, that is a namespace for functions that convert
44/// arbitrary UTF-8 codepoint sequences to JSON strings and vice versa. The
45/// rules for these conversions are outlined below in {JSON Strings} and
46/// detailed in: https://www.rfc-editor.org/rfc/rfc8259#section-7 (RFC8259)
47///
48/// This utility provides two key functions:
49///
50/// * `writeString`: Given an arbitrary UTF-8 codepoint sequence, generate a
51/// JSON string representing the same codepoints.
52/// * `readString`: Given a JSON string (e.g., the output of `writeString`),
53/// generate the equivalent sequence of UTF-8 code points.
54///
55/// When using these functions, a UTF-8 codepoint sequence is always preserved
56/// on the round trip to JSON string and back; however, since there are
57/// equivalent allowed representations of a JSON string, the converse is not
58/// guaranteed.
59///
60/// ## JSON Strings {#bdljsn_stringutil-json-strings}
61///
62///
63/// JSON strings consist of UTF-8 codepoints surround by double quotes (i.e.,
64/// '\"') Within those double quotes certain characters *must* be escaped (i.e.,
65/// replaced with some alternative, multi-byte representation). Those
66/// characters are:
67///
68/// * quotation marks
69/// * backslashes (a.k.a., a "reverse solidus")
70/// * the "control characters" in the range `U+0000` to `U+001F` (inclusive).
71///
72/// Each of the above characters can be escaped by replacing it with the six
73/// byte sequence consisting of:
74///
75/// - a backslash,
76/// - a lower-case `u`, and
77/// - the Unicode value expressed as four hexadecimal digits.
78///
79/// For example, the character that rings the console bell is represented as
80/// '\u0007'. Note that the hexadecimal digits can use upper or lower case
81/// letters but the lead `u` character must be lower case. See {Strictness}.
82///
83/// Seven of the characters that must be escaped (and `/`, which *may* be
84/// escaped) can be alternatively represented by special, 2-byte sequences:
85/// @code
86/// +---------+-----------------+---------------+---------------+
87/// | Unicode | Description | 6-byte escape | 2-byte escape |
88/// +---------+-----------------+---------------+---------------+
89/// | U+0022 | quotation mark | \u0022 | \" |
90/// | U+005C | backslash | \u005c | \\ |
91/// | U+002F | slash | \u002f | \/ |
92/// | U+0008 | backspace | \u0008 | \b |
93/// | U+000C | form feed | \u000C | \f |
94/// | U+000A | line feed | \u000A | \n |
95/// | U+000D | carriage return | \u000D | \r |
96/// | U+0009 | tab | \u0009 | \t |
97/// +---------+-----------------+---------------+---------------+
98/// @endcode
99/// Note that the above set is similar to but not identical to the set of two
100/// byte `char` literals supported by C++. For example, '\0' (null) and '\a'
101/// (bell) are not included above.
102///
103/// ### Guarantees: Arbitrary UTF-8 to JSON String {#bdljsn_stringutil-guarantees-arbitrary-utf-8-to-json-string}
104///
105///
106/// * No UTF-8 characters in the *Basic* *Multilingual* *Plane* are escaped
107/// unless they are in the set that *must* be escaped (or are `/` with the
108/// appropriate flags).
109/// * When a character must be escaped, the 6-byte (hexadecimal) representation
110/// is used only if no 2-byte escape exists.
111/// * When a 6-byte (hexadecimal) representation is used, hexadecimal letters
112/// are in upper case.
113/// * All UTF-8 characters outside of the *Basic* *Multilingual* *Plane*
114/// are represented by two, adjacent 6-byte hexadecimal escape
115/// sequences. For details, see:
116/// https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
117///
118/// ## Strictness {#bdljsn_stringutil-strictness}
119///
120///
121/// By default, the `bdljsn::StringUtil` read and write methods strictly follow
122/// the RFC8259 standard. Variances from those rules are expressed using
123/// `bdljsn::StringUtil::Flags`, an `enum` of flag values that can be set in the
124/// optional `flags` parameter of the decoding methods. Multiple flags can be
125/// bitwise set in `flags`; however, currently, just one variance flag is
126/// defined.
127///
128/// ### Example Variance {#bdljsn_stringutil-example-variance}
129///
130///
131/// RFC8259 specifies that the 6-byte Unicode escape sequence start with a
132/// backslash, `\`, and lower-case `u`. However, if the
133/// `bdljsn::StringUtil::e_ACCEPT_CAPITAL_UNICODE_ESCAPE` is set, an upper-case
134/// `U` is accepted as well. Thus, both '\u0007' and '\U0007' would be
135/// interpreted as the BELL character.
136///
137/// ## Usage {#bdljsn_stringutil-usage}
138///
139///
140/// This section illustrates intended use of this component.
141///
142/// ### Example 1: Encoding and Decoding a JSON String {#bdljsn_stringutil-example-1-encoding-and-decoding-a-json-string}
143///
144///
145/// First, we initialize a string with a valid sequence of UTF-8 codepoints.
146/// @code
147/// bsl::string initial("Does the name \"Ivan Pavlov\" ring a bell\a?\n");
148/// assert(bdlde::Utf8Util::isValid(initial));
149/// @endcode
150/// Notice that, as required by C++ syntax, several characters are represented
151/// by their two-character escape sequence: double quote (twice), bell, and
152/// newline.
153///
154/// Then, we examine the string as output:
155/// @code
156/// bsl::cout << initial << bsl::endl;
157/// @endcode
158/// and observe:
159/// @code
160/// Does the name "Ivan Pavlov" ring a bell?
161///
162/// @endcode
163/// Notice that the backslash characters (having served their purpose of giving
164/// special meaning to the subsequent character) are not shown. The BELL and
165/// NEWLINE characters are output but are not visible.
166///
167/// Now, we generate JSON string equivalent of the `initial` string.
168/// @code
169/// bsl::ostringstream oss;
170///
171/// int rcEncode = bdljsn::StringUtil::writeString(oss, initial);
172/// assert(0 == rcEncode);
173///
174/// bsl::string jsonCompatibleString = oss.str();
175/// bsl::cout << jsonCompatibleString << bsl::endl;
176/// @endcode
177/// and observed how the `initial` string is represented for JSON:
178/// @code
179/// "Does the name \"Ivan Pavlov\" ring a bell\u0007?\n"
180/// @endcode
181/// Notice that:
182/// * The entire string is delimited by double quotes.
183/// * The interior double quotes and new line are represented by two character
184/// escape sequences (as they were in the C++ string literal.
185/// * Since JSON does not have a two character escape sequence for the BELL
186/// character, '\u0007', the 6-byte Unicode representation is used.
187///
188/// Finally, we convert the `jsonCompatibleString` back to its original content:
189/// @code
190/// bsl::string fromJsonString;
191/// const int rcDecode = bdljsn::StringUtil::readString(&fromJsonString,
192/// jsonCompatibleString);
193/// assert(0 == rcDecode);
194/// assert(initial == fromJsonString);
195///
196/// bsl::cout << fromJsonString << bsl::endl;
197/// @endcode
198/// and observe (again):
199/// @code
200/// Does the name "Ivan Pavlov" ring a bell?
201///
202/// @endcode
203/// @}
204/** @} */
205/** @} */
206
207/** @addtogroup bdl
208 * @{
209 */
210/** @addtogroup bdljsn
211 * @{
212 */
213/** @addtogroup bdljsn_stringutil
214 * @{
215 */
216
217#include <bdlscm_version.h>
218
219#include <bsls_assert.h>
220
221#include <bsl_ostream.h>
222#include <bsl_string.h>
223#include <bsl_string_view.h>
224
225
226namespace bdljsn {
227
228 // =================
229 // struct StringUtil
230 // =================
231
232/// This class provides utility functions for converting arbitrary UTF-8
233/// sequences into JSON strings and visa versa. See @ref bdljsn_stringutil-json-strings for
234/// details of these transformations.
235///
236/// See @ref bdljsn_stringutil
238
239 public:
240 // TYPES
246
247 private:
248 // PRIVATE CLASS METHODS
249
250 /// Load to the specified `value` the UTF-8 codepoint sequence equivalent
251 /// to the specified (JSON) `string` (see @ref bdljsn_stringutil-json-strings ). Return 0 on
252 /// success and a non-zero value otherwise. Optionally specify `flags` to
253 /// request variances from certain rules of JSON decoding (see
254 /// @ref bdljsn_stringutil-strictness ).
255 template <class STRING>
256 static int readStringImp(STRING *value,
257 const bsl::string_view& string,
258 int flags);
259
260 public:
261 // CLASS METHODS
262
263 /// Load to the specified `value` the UTF-8 codepoint sequence equivalent
264 /// to the specified (JSON) `string` (see @ref bdljsn_stringutil-json-strings ). Return 0 on
265 /// success and a non-zero value otherwise. Optionally specify `flags` to
266 /// request variances from certain rules of JSON decoding (see
267 /// @ref bdljsn_stringutil-strictness ).
268 static int readString(bsl::string *value,
269 const bsl::string_view& string,
270 int flags = e_NONE);
271 static int readString(std::string *value,
272 const bsl::string_view& string,
273 int flags = e_NONE);
274#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
275 static int readString(std::pmr::string *value,
276 const bsl::string_view& string,
277 int flags = e_NONE);
278#endif
279
280 /// Load to the specified `value` the UTF-8 codepoint sequence equivalent
281 /// to the specified `string`, that is JSON-compliant absent the leading
282 /// and trailing double quote characters (see @ref bdljsn_stringutil-json-strings ). Return 0
283 /// on success and a non-zero value otherwise. Optionally specify `flags`
284 /// to request variances from certain rules of JSON decoding (see
285 /// @ref bdljsn_stringutil-strictness ).
287 const bsl::string_view& string,
288 int flags = e_NONE);
289 static int readUnquotedString(std::string *value,
290 const bsl::string_view& string,
291 int flags = e_NONE);
292#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
293 static int readUnquotedString(std::pmr::string *value,
294 const bsl::string_view& string,
295 int flags = e_NONE);
296#endif
297
298 /// Write to the specified `stream` a JSON-compliant string that is
299 /// equivalent to the specified `string`, an arbitrary UTF-8 codepoint
300 /// sequence. Return 0 on success and a non-zero value otherwise. The
301 /// operation fails if `string` is not a sequence of UTF-8 codepoints or if
302 /// there is an error writing to `stream`. See
303 /// @ref bdljsn_stringutil-guarantees-arbitrary-utf-8-to-json-string for further details.
304 static int writeString(bsl::ostream& stream,
305 const bsl::string_view& string,
306 int flags = e_NONE);
307};
308
309// ============================================================================
310// INLINE DEFINITIONS
311// ============================================================================
312
313 // -----------------
314 // struct StringUtil
315 // -----------------
316
317// PRIVATE CLASS METHODS
318template <class STRING>
319inline
320int StringUtil::readStringImp(STRING *value,
321 const bsl::string_view& string,
322 int flags)
323{
324 BSLS_ASSERT(value);
325
326 if (2 > string.size()) {
327 return -1; // RETURN
328 }
329
330 if (string[0] != '"' && string[string.size() - 1] != '"') {
331 return -1; // RETURN
332 }
333
334 const bsl::string_view contents = string.substr(1, string.size() - 2);
335 return readUnquotedString(value, contents, flags);
336}
337
338// CLASS METHODS
339
340inline
342 const bsl::string_view& string,
343 int flags)
344{
345 return readStringImp(value, string, flags);
346}
347
348inline
349int StringUtil::readString(std::string *value,
350 const bsl::string_view& string,
351 int flags)
352{
353 return readStringImp(value, string, flags);
354}
355
356#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
357inline
358int StringUtil::readString(std::pmr::string *value,
359 const bsl::string_view& string,
360 int flags)
361{
362 return readStringImp(value, string, flags);
363}
364#endif
365
366} // close package namespace
367
368
369#endif
370
371// ----------------------------------------------------------------------------
372// Copyright 2022 Bloomberg Finance L.P.
373//
374// Licensed under the Apache License, Version 2.0 (the "License");
375// you may not use this file except in compliance with the License.
376// You may obtain a copy of the License at
377//
378// http://www.apache.org/licenses/LICENSE-2.0
379//
380// Unless required by applicable law or agreed to in writing, software
381// distributed under the License is distributed on an "AS IS" BASIS,
382// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
383// See the License for the specific language governing permissions and
384// limitations under the License.
385// ----------------------------- END-OF-FILE ----------------------------------
386
387/** @} */
388/** @} */
389/** @} */
Definition bslstl_stringview.h:471
BSLS_KEYWORD_CONSTEXPR_CPP14 basic_string_view substr(size_type position=0, size_type numChars=npos) const
Definition bslstl_stringview.h:2027
Definition bslstl_string.h:1252
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition bdljsn_error.h:142
Definition bdljsn_stringutil.h:237
static int writeString(bsl::ostream &stream, const bsl::string_view &string, int flags=e_NONE)
Flags
Definition bdljsn_stringutil.h:241
@ e_ACCEPT_CAPITAL_UNICODE_ESCAPE
Definition bdljsn_stringutil.h:243
@ e_NONE
Definition bdljsn_stringutil.h:242
@ e_NO_ESCAPING_FORWARD_SLASH
Definition bdljsn_stringutil.h:244
static int readUnquotedString(std::string *value, const bsl::string_view &string, int flags=e_NONE)
static int readString(bsl::string *value, const bsl::string_view &string, int flags=e_NONE)
Definition bdljsn_stringutil.h:341
static int readUnquotedString(bsl::string *value, const bsl::string_view &string, int flags=e_NONE)