@@ -250,6 +250,33 @@ std::string DumpImportList(const FileDescriptor* file) {
250
250
return ret;
251
251
}
252
252
253
+ namespace {
254
+
255
+ // Escape a string for use in a Ruby string literal. This is a superset of
256
+ // absl::CHexEscape() that also includes handling of the following characters:
257
+ // - # (hashmark)
258
+ //
259
+ // This is needed because Ruby double-quoted string literals interpolate the
260
+ // contents of the string, and the hashmark character is used in the
261
+ // interpolation syntax. Informed by MRI Ruby's implementation of String#dump.
262
+ std::string RubyEscape (absl::string_view s) {
263
+ std::string c_escaped = absl::CHexEscape (s);
264
+ std::string result;
265
+ result.reserve (c_escaped.length ());
266
+ for (size_t i = 0 ; i < c_escaped.length (); ++i) {
267
+ if (c_escaped[i] == ' #' &&
268
+ (i + 1 < c_escaped.length () &&
269
+ (c_escaped[i + 1 ] == ' {' || c_escaped[i + 1 ] == ' $' ||
270
+ c_escaped[i + 1 ] == ' @' ))) {
271
+ absl::StrAppend (&result, " \\ " );
272
+ }
273
+ absl::StrAppend (&result, c_escaped.substr (i, 1 ));
274
+ }
275
+ return result;
276
+ }
277
+
278
+ } // namespace
279
+
253
280
void GenerateBinaryDescriptor (const FileDescriptor* file, io::Printer* printer,
254
281
std::string* error) {
255
282
printer->Print (R"(
@@ -259,9 +286,8 @@ pool = Google::Protobuf::DescriptorPool.generated_pool
259
286
pool.add_serialized_file(descriptor_data)
260
287
261
288
)" ,
262
- " descriptor_data" ,
263
- absl::CHexEscape (SerializedDescriptor (file)), " imports" ,
264
- DumpImportList (file));
289
+ " descriptor_data" , RubyEscape (SerializedDescriptor (file)),
290
+ " imports" , DumpImportList (file));
265
291
}
266
292
267
293
bool GenerateFile (const FileDescriptor* file, io::Printer* printer,
0 commit comments