1
+ /*-
2
+ * #%L
3
+ * Java ECS logging
4
+ * %%
5
+ * Copyright (C) 2019 Elastic and contributors
6
+ * %%
7
+ * Licensed to Elasticsearch B.V. under one or more contributor
8
+ * license agreements. See the NOTICE file distributed with
9
+ * this work for additional information regarding copyright
10
+ * ownership. Elasticsearch B.V. licenses this file to you under
11
+ * the Apache License, Version 2.0 (the "License"); you may
12
+ * not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * http://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing,
18
+ * software distributed under the License is distributed on an
19
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ * KIND, either express or implied. See the License for the
21
+ * specific language governing permissions and limitations
22
+ * under the License.
23
+ * #L%
24
+ */
1
25
package co .elastic .logging ;
2
26
3
27
/**
4
- * This class is borrowed from <a href="https://github.com/FasterXML/jackson-core">Jackson</a>.
28
+ * This class is based on com.fasterxml.jackson.core.io.CharTypes,
29
+ * under Apache License 2.0
5
30
*/
6
31
public final class JsonUtils {
7
32
8
- private static final char [] HC = "0123456789ABCDEF" .toCharArray ();
33
+ private final static char [] HC = "0123456789ABCDEF" .toCharArray ();
9
34
10
35
/**
11
- * Read-only encoding table for first 128 Unicode code points (single-byte UTF-8 characters).
12
- * Value of 0 means "no escaping"; other positive values that value is character
13
- * to use after backslash; and negative values that generic (backslash - u)
14
- * escaping is to be used.
36
+ * Lookup table used for determining which output characters in
37
+ * 7-bit ASCII range need to be quoted.
15
38
*/
16
- private static final int [] ESC_CODES ;
39
+ private final static int [] sOutputEscapes128 ;
40
+
17
41
static {
18
- final int [] table = new int [128 ];
42
+ int [] table = new int [128 ];
19
43
// Control chars need generic escape sequence
20
44
for (int i = 0 ; i < 32 ; ++i ) {
21
45
// 04-Mar-2011, tatu: Used to use "-(i + 1)", replaced with constant
22
46
table [i ] = -1 ;
23
47
}
24
- /* Others (and some within that range too) have explicit shorter
25
- * sequences
26
- */
48
+ // Others (and some within that range too) have explicit shorter sequences
27
49
table ['"' ] = '"' ;
28
50
table ['\\' ] = '\\' ;
29
51
// Escaping of slash is optional, so let's not add it
@@ -32,72 +54,40 @@ public final class JsonUtils {
32
54
table [0x0C ] = 'f' ;
33
55
table [0x0A ] = 'n' ;
34
56
table [0x0D ] = 'r' ;
35
- ESC_CODES = table ;
36
- }
37
-
38
- /**
39
- * Temporary buffer used for composing quote/escape sequences
40
- */
41
- private final static ThreadLocal <char []> _qbufLocal = new ThreadLocal <>();
42
-
43
- private static char [] getQBuf () {
44
- char [] _qbuf = _qbufLocal .get ();
45
- if (_qbuf == null ) {
46
- _qbuf = new char [6 ];
47
- _qbuf [0 ] = '\\' ;
48
- _qbuf [2 ] = '0' ;
49
- _qbuf [3 ] = '0' ;
50
-
51
- _qbufLocal .set (_qbuf );
52
- }
53
- return _qbuf ;
57
+ sOutputEscapes128 = table ;
54
58
}
55
59
56
- /**
57
- * Quote text contents using JSON standard quoting, and append results to a supplied {@link StringBuilder}.
58
- */
59
- public static void quoteAsString (final CharSequence input , final StringBuilder output ) {
60
- final char [] qbuf = getQBuf ();
61
- final int escCodeCount = ESC_CODES .length ;
62
- int inPtr = 0 ;
63
- final int inputLen = input .length ();
64
-
65
- outer :
66
- while (inPtr < inputLen ) {
67
- tight_loop :
68
- while (true ) {
69
- final char c = input .charAt (inPtr );
70
- if (c < escCodeCount && ESC_CODES [c ] != 0 ) {
71
- break tight_loop ;
72
- }
73
- output .append (c );
74
- if (++inPtr >= inputLen ) {
75
- break outer ;
76
- }
60
+ public static void quoteAsString (CharSequence content , StringBuilder sb ) {
61
+ final int [] escCodes = sOutputEscapes128 ;
62
+ final int escLen = escCodes .length ;
63
+ for (int i = 0 , len = content .length (); i < len ; ++i ) {
64
+ char c = content .charAt (i );
65
+ if (c >= escLen || escCodes [c ] == 0 ) {
66
+ sb .append (c );
67
+ continue ;
77
68
}
78
- // something to escape; 2 or 6-char variant?
79
- final char d = input .charAt (inPtr ++);
80
- final int escCode = ESC_CODES [d ];
81
- final int length = (escCode < 0 )
82
- ? _appendNumeric (d , qbuf )
83
- : _appendNamed (escCode , qbuf );
69
+ sb .append ('\\' );
70
+ int escCode = escCodes [c ];
71
+ if (escCode < 0 ) { // generic quoting (hex value)
72
+ // The only negative value sOutputEscapes128 returns
73
+ // is CharacterEscapes.ESCAPE_STANDARD, which mean
74
+ // appendQuotes should encode using the Unicode encoding;
75
+ // not sure if this is the right way to encode for
76
+ // CharacterEscapes.ESCAPE_CUSTOM or other (future)
77
+ // CharacterEscapes.ESCAPE_XXX values.
84
78
85
- output .append (qbuf , 0 , length );
79
+ // We know that it has to fit in just 2 hex chars
80
+ sb .append ('u' );
81
+ sb .append ('0' );
82
+ sb .append ('0' );
83
+ int value = c ; // widening
84
+ sb .append (HC [value >> 4 ]);
85
+ sb .append (HC [value & 0xF ]);
86
+ } else { // "named", i.e. prepend with slash
87
+ sb .append ((char ) escCode );
88
+ }
86
89
}
87
90
}
88
91
89
- private static int _appendNumeric (final int value , final char [] qbuf ) {
90
- qbuf [1 ] = 'u' ;
91
- // We know it's a control char, so only the last 2 chars are non-0
92
- qbuf [4 ] = HC [value >> 4 ];
93
- qbuf [5 ] = HC [value & 0xF ];
94
- return 6 ;
95
- }
96
-
97
- private static int _appendNamed (final int esc , final char [] qbuf ) {
98
- qbuf [1 ] = (char ) esc ;
99
- return 2 ;
100
- }
101
-
102
92
}
103
93
0 commit comments