1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/json/string_escape.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversion_utils.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/third_party/icu/icu_utf.h"
19 // Format string for printing a \uXXXX escape sequence.
20 const char kU16EscapeFormat
[] = "\\u%04X";
22 // The code point to output for an invalid input code unit.
23 const uint32 kReplacementCodePoint
= 0xFFFD;
25 // Used below in EscapeSpecialCodePoint().
26 COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c
);
28 // Try to escape the |code_point| if it is a known special character. If
29 // successful, returns true and appends the escape sequence to |dest|. This
30 // isn't required by the spec, but it's more readable by humans.
31 bool EscapeSpecialCodePoint(uint32 code_point
, std::string
* dest
) {
32 // WARNING: if you add a new case here, you need to update the reader as well.
33 // Note: \v is in the reader, but not here since the JSON spec doesn't
57 // Escape < to prevent script execution; escaping > is not necessary and
58 // not doing so save a few bytes.
60 dest
->append("\\u003C");
69 bool EscapeJSONStringImpl(const S
& str
, bool put_in_quotes
, std::string
* dest
) {
70 bool did_replacement
= false;
75 // Casting is necessary because ICU uses int32. Try and do so safely.
76 CHECK_LE(str
.length(), static_cast<size_t>(kint32max
));
77 const int32 length
= static_cast<int32
>(str
.length());
79 for (int32 i
= 0; i
< length
; ++i
) {
81 if (!ReadUnicodeCharacter(str
.data(), length
, &i
, &code_point
)) {
82 code_point
= kReplacementCodePoint
;
83 did_replacement
= true;
86 if (EscapeSpecialCodePoint(code_point
, dest
))
89 // Escape non-printing characters.
91 base::StringAppendF(dest
, kU16EscapeFormat
, code_point
);
93 WriteUnicodeCharacter(code_point
, dest
);
99 return !did_replacement
;
104 bool EscapeJSONString(const StringPiece
& str
,
107 return EscapeJSONStringImpl(str
, put_in_quotes
, dest
);
110 bool EscapeJSONString(const StringPiece16
& str
,
113 return EscapeJSONStringImpl(str
, put_in_quotes
, dest
);
116 std::string
GetQuotedJSONString(const StringPiece
& str
) {
118 bool ok
= EscapeJSONStringImpl(str
, true, &dest
);
123 std::string
GetQuotedJSONString(const StringPiece16
& str
) {
125 bool ok
= EscapeJSONStringImpl(str
, true, &dest
);
130 std::string
EscapeBytesAsInvalidJSONString(const StringPiece
& str
,
131 bool put_in_quotes
) {
137 for (StringPiece::const_iterator it
= str
.begin(); it
!= str
.end(); ++it
) {
138 ToUnsigned
<StringPiece::value_type
>::Unsigned c
= *it
;
139 if (EscapeSpecialCodePoint(c
, &dest
))
142 if (c
< 32 || c
> 126)
143 base::StringAppendF(&dest
, kU16EscapeFormat
, c
);