Skip to content

Commit 3a6e134

Browse files
committed
[C++] Escape var data character strings when pretty printing codecs as JSON. Issue aeron-io#718.
1 parent 83e514a commit 3a6e134

File tree

1 file changed

+57
-15
lines changed

1 file changed

+57
-15
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ private static void generateGroupClassHeader(
302302
indent + " *m_positionPtr = sbeCheckPosition(position);\n" +
303303
indent + " }\n\n" +
304304

305+
indent + " SBE_NODISCARD std::string sbeEscapeJson(const std::string &s) const SBE_NOEXCEPT\n" +
306+
indent + " {\n" +
307+
indent + " return ::sbeEscapeJsonString(s);\n" +
308+
indent + " }\n\n" +
309+
305310
indent + " SBE_NODISCARD inline std::uint64_t count() const SBE_NOEXCEPT\n" +
306311
indent + " {\n" +
307312
indent + " return m_count;\n" +
@@ -1010,7 +1015,9 @@ private static CharSequence generateFileHeader(
10101015
"#include <cstring>\n" +
10111016
"#include <limits>\n" +
10121017
"#include <stdexcept>\n\n" +
1013-
"#include <ostream>\n\n" +
1018+
"#include <ostream>\n" +
1019+
"#include <sstream>\n" +
1020+
"#include <iomanip>\n\n" +
10141021

10151022
"#if defined(WIN32) || defined(_WIN32)\n" +
10161023
"# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)\n" +
@@ -1053,10 +1060,12 @@ private static CharSequence generateFileHeader(
10531060
"#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()\n" +
10541061
"#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()\n" +
10551062
"#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()\n" +
1056-
"#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()\n",
1063+
"#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()\n\n",
10571064
String.join("_", namespaces).toUpperCase(),
10581065
className.toUpperCase()));
10591066

1067+
sb.append(generateEscapeFunction());
1068+
10601069
if (typesToInclude != null && typesToInclude.size() != 0)
10611070
{
10621071
sb.append("\n");
@@ -1073,12 +1082,35 @@ private static CharSequence generateFileHeader(
10731082
return sb;
10741083
}
10751084

1085+
private static CharSequence generateEscapeFunction()
1086+
{
1087+
return
1088+
"#ifndef _SBE_JSON_ESCAPE_FUNC_H_\n" +
1089+
"#define _SBE_JSON_ESCAPE_FUNC_H_\n" +
1090+
"static inline std::string sbeEscapeJsonString(const std::string &s)\n" +
1091+
"{\n" +
1092+
" std::ostringstream oss;\n\n" +
1093+
" for (auto c = s.cbegin(); c != s.cend(); c++)\n" +
1094+
" {\n" +
1095+
" if (*c == '\"' || *c == '\\\\' || ('\\x00' <= *c && *c <= '\\x1f'))\n" +
1096+
" {\n" +
1097+
" oss << \"\\\\u\"" + " << std::hex << std::setw(4) << std::setfill('0') << (int)*c;\n" +
1098+
" }\n" +
1099+
" else\n" +
1100+
" {\n" +
1101+
" oss << *c;\n" +
1102+
" }\n" +
1103+
" }\n\n" +
1104+
" return oss.str();\n" +
1105+
"}\n" +
1106+
"#endif\n\n";
1107+
}
1108+
10761109
private static CharSequence generateClassDeclaration(final String className)
10771110
{
1078-
return String.format(
1079-
"class %s\n" +
1080-
"{\n",
1081-
className);
1111+
return
1112+
"class " + className + "\n" +
1113+
"{\n";
10821114
}
10831115

10841116
private static CharSequence generateEnumDeclaration(final String name)
@@ -1903,6 +1935,11 @@ private CharSequence generateMessageFlyweightCode(final String className, final
19031935
" m_position = sbeCheckPosition(position);\n" +
19041936
" }\n\n" +
19051937

1938+
" SBE_NODISCARD std::string sbeEscapeJson(const std::string &s) const SBE_NOEXCEPT\n" +
1939+
" {\n" +
1940+
" return ::sbeEscapeJsonString(s);\n" +
1941+
" }\n\n" +
1942+
19061943
" SBE_NODISCARD std::uint64_t encodedLength() const SBE_NOEXCEPT\n" +
19071944
" {\n" +
19081945
" return sbePosition() - m_offset;\n" +
@@ -2320,7 +2357,7 @@ private CharSequence generateDisplay(
23202357
indent + " builder << writer.sbeTemplateId();\n" +
23212358
indent + " builder << \", \";\n\n" +
23222359
"%2$s" +
2323-
indent + " builder << '}';\n" +
2360+
indent + " builder << '}';\n\n" +
23242361
indent + " return builder;\n" +
23252362
indent + "}\n",
23262363
formatClassName(name),
@@ -2341,7 +2378,7 @@ private CharSequence generateGroupDisplay(
23412378
indent + "{\n" +
23422379
indent + " builder << '{';\n" +
23432380
"%2$s" +
2344-
indent + " builder << '}';\n" +
2381+
indent + " builder << '}';\n\n" +
23452382
indent + " return builder;\n" +
23462383
indent + "}\n",
23472384
formatClassName(name),
@@ -2360,7 +2397,7 @@ private CharSequence generateCompositeDisplay(
23602397
indent + "{\n" +
23612398
indent + " builder << '{';\n" +
23622399
"%2$s" +
2363-
indent + " builder << '}';\n" +
2400+
indent + " builder << '}';\n\n" +
23642401
indent + " return builder;\n" +
23652402
indent + "}\n\n",
23662403
formatClassName(name),
@@ -2453,20 +2490,25 @@ private CharSequence appendDisplay(
24532490
atLeastOne[0] = true;
24542491

24552492
final String characterEncoding = varData.get(i + 3).encoding().characterEncoding();
2456-
final String getAsStringFunction = "get" + toUpperFirstChar(varDataToken.name()) + "AsString().c_str()";
24572493
sb.append(indent + "builder << R\"(\"" + varDataToken.name() + "\": )\";\n");
24582494

24592495
if (null == characterEncoding)
24602496
{
2497+
final String getAsStringFunction =
2498+
"writer.get" + toUpperFirstChar(varDataToken.name()) + "AsString().c_str()";
2499+
24612500
sb.append(
24622501
indent + "builder << '\"' <<\n" +
2463-
indent + INDENT + "writer." + getAsStringFunction + " << '\"';\n\n");
2502+
indent + INDENT + getAsStringFunction + " << '\"';\n\n");
24642503
}
24652504
else
24662505
{
2506+
final String getAsStringFunction =
2507+
"writer.sbeEscapeJson(writer.get" + toUpperFirstChar(varDataToken.name()) + "AsString()).c_str()";
2508+
24672509
sb.append(
24682510
indent + "builder << '\"' <<\n" +
2469-
indent + INDENT + "writer." + getAsStringFunction + " << '\"';\n\n");
2511+
indent + INDENT + getAsStringFunction + " << '\"';\n\n");
24702512
}
24712513

24722514
i += varDataToken.componentTokenCount();
@@ -2510,8 +2552,8 @@ private CharSequence writeTokenDisplay(
25102552
{
25112553
sb.append(
25122554
indent + "builder << '\"';\n" +
2513-
indent + "for (size_t i = 0;\n" +
2514-
indent + " i < " + fieldName + "Length() && " + fieldName + "(i) > 0;\n" +
2555+
indent + "for (size_t i = 0, length = " + fieldName + "Length();\n" +
2556+
indent + " i < length && " + fieldName + "(i) > 0;\n" +
25152557
indent + " i++)\n" +
25162558
indent + "{\n" +
25172559
indent + " builder << (char)" + fieldName + "(i);\n" +
@@ -2524,7 +2566,7 @@ private CharSequence writeTokenDisplay(
25242566
indent + "builder << '[';\n" +
25252567
indent + "if (" + fieldName + "Length() > 0)\n" +
25262568
indent + "{\n" +
2527-
indent + " for (size_t i = 0; i < " + fieldName + "Length(); i++)\n" +
2569+
indent + " for (size_t i = 0, length = " + fieldName + "Length(); i < length; i++)\n" +
25282570
indent + " {\n" +
25292571
indent + " if (i)\n" +
25302572
indent + " {\n" +

0 commit comments

Comments
 (0)