@@ -15,6 +15,14 @@ library Strings {
15
15
16
16
bytes16 private constant HEX_DIGITS = "0123456789abcdef " ;
17
17
uint8 private constant ADDRESS_LENGTH = 20 ;
18
+ uint256 private constant SPECIAL_CHARS_LOOKUP =
19
+ (1 << 0x08 ) | // backspace
20
+ (1 << 0x09 ) | // tab
21
+ (1 << 0x0a ) | // newline
22
+ (1 << 0x0c ) | // form feed
23
+ (1 << 0x0d ) | // carriage return
24
+ (1 << 0x22 ) | // double quote
25
+ (1 << 0x5c ); // backslash
18
26
19
27
/**
20
28
* @dev The `value` string doesn't fit in the specified `length`.
@@ -426,6 +434,43 @@ library Strings {
426
434
return value;
427
435
}
428
436
437
+ /**
438
+ * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
439
+ *
440
+ * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
441
+ */
442
+ function escapeJSON (string memory input ) internal pure returns (string memory ) {
443
+ bytes memory buffer = bytes (input);
444
+ bytes memory output = new bytes (2 * buffer.length ); // worst case scenario
445
+ uint256 outputLength = 0 ;
446
+
447
+ for (uint256 i; i < buffer.length ; ++ i) {
448
+ bytes1 char = bytes1 (_unsafeReadBytesOffset (buffer, i));
449
+ if (((SPECIAL_CHARS_LOOKUP & (1 << uint8 (char))) != 0 )) {
450
+ output[outputLength++ ] = "\ \" ;
451
+ if (char == 0x08) output[outputLength++] = " b";
452
+ else if (char == 0x09) output[outputLength++] = " t";
453
+ else if (char == 0x0a) output[outputLength++] = " n";
454
+ else if (char == 0x0c) output[outputLength++] = " f";
455
+ else if (char == 0x0d) output[outputLength++] = " r";
456
+ else if (char == 0x5c) output[outputLength++] = " \\";
457
+ else if (char == 0x22 ) {
458
+ // solhint-disable-next-line quotes
459
+ output[outputLength++ ] = '" ' ;
460
+ }
461
+ } else {
462
+ output[outputLength++ ] = char;
463
+ }
464
+ }
465
+ // write the actual length and deallocate unused memory
466
+ assembly ("memory-safe" ) {
467
+ mstore (output, outputLength)
468
+ mstore (0x40 , add (output, shl (5 , shr (5 , add (outputLength, 63 )))))
469
+ }
470
+
471
+ return string (output);
472
+ }
473
+
429
474
/**
430
475
* @dev Reads a bytes32 from a bytes array without bounds checking.
431
476
*
0 commit comments