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");
62 // Escape the "Line Separator" and "Paragraph Separator" characters, since
63 // they should be treated like a new line \r or \n.
65 dest
->append("\\u2028");
68 dest
->append("\\u2029");
77 bool EscapeJSONStringImpl(const S
& str
, bool put_in_quotes
, std::string
* dest
) {
78 bool did_replacement
= false;
83 // Casting is necessary because ICU uses int32. Try and do so safely.
84 CHECK_LE(str
.length(), static_cast<size_t>(kint32max
));
85 const int32 length
= static_cast<int32
>(str
.length());
87 for (int32 i
= 0; i
< length
; ++i
) {
89 if (!ReadUnicodeCharacter(str
.data(), length
, &i
, &code_point
)) {
90 code_point
= kReplacementCodePoint
;
91 did_replacement
= true;
94 if (EscapeSpecialCodePoint(code_point
, dest
))
97 // Escape non-printing characters.
99 base::StringAppendF(dest
, kU16EscapeFormat
, code_point
);
101 WriteUnicodeCharacter(code_point
, dest
);
105 dest
->push_back('"');
107 return !did_replacement
;
112 bool EscapeJSONString(const StringPiece
& str
,
115 return EscapeJSONStringImpl(str
, put_in_quotes
, dest
);
118 bool EscapeJSONString(const StringPiece16
& str
,
121 return EscapeJSONStringImpl(str
, put_in_quotes
, dest
);
124 std::string
GetQuotedJSONString(const StringPiece
& str
) {
126 bool ok
= EscapeJSONStringImpl(str
, true, &dest
);
131 std::string
GetQuotedJSONString(const StringPiece16
& str
) {
133 bool ok
= EscapeJSONStringImpl(str
, true, &dest
);
138 std::string
EscapeBytesAsInvalidJSONString(const StringPiece
& str
,
139 bool put_in_quotes
) {
145 for (StringPiece::const_iterator it
= str
.begin(); it
!= str
.end(); ++it
) {
146 unsigned char c
= *it
;
147 if (EscapeSpecialCodePoint(c
, &dest
))
150 if (c
< 32 || c
> 126)
151 base::StringAppendF(&dest
, kU16EscapeFormat
, c
);