001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.util; 018 019import com.fasterxml.jackson.core.io.CharTypes; 020 021/** 022 * This class is borrowed from <a href="https://github.com/FasterXML/jackson-core">Jackson</a>. 023 */ 024public final class JsonUtils { 025 026 private final static char[] HC = CharTypes.copyHexChars(); 027 028 /** 029 * Temporary buffer used for composing quote/escape sequences 030 */ 031 private final static ThreadLocal<char[]> _qbufLocal = new ThreadLocal<>(); 032 033 private static char[] getQBuf() { 034 char[] _qbuf = _qbufLocal.get(); 035 if (_qbuf == null) { 036 _qbuf = new char[6]; 037 _qbuf[0] = '\\'; 038 _qbuf[2] = '0'; 039 _qbuf[3] = '0'; 040 041 _qbufLocal.set(_qbuf); 042 } 043 return _qbuf; 044 } 045 046 /** 047 * Quote text contents using JSON standard quoting, and append results to a supplied {@link StringBuilder}. 048 */ 049 public static void quoteAsString(CharSequence input, StringBuilder output) { 050 final char[] qbuf = getQBuf(); 051 final int[] escCodes = CharTypes.get7BitOutputEscapes(); 052 final int escCodeCount = escCodes.length; 053 int inPtr = 0; 054 final int inputLen = input.length(); 055 056 outer: 057 while (inPtr < inputLen) { 058 tight_loop: 059 while (true) { 060 char c = input.charAt(inPtr); 061 if (c < escCodeCount && escCodes[c] != 0) { 062 break tight_loop; 063 } 064 output.append(c); 065 if (++inPtr >= inputLen) { 066 break outer; 067 } 068 } 069 // something to escape; 2 or 6-char variant? 070 char d = input.charAt(inPtr++); 071 int escCode = escCodes[d]; 072 int length = (escCode < 0) 073 ? _appendNumeric(d, qbuf) 074 : _appendNamed(escCode, qbuf); 075 076 output.append(qbuf, 0, length); 077 } 078 } 079 080 private static int _appendNumeric(int value, char[] qbuf) { 081 qbuf[1] = 'u'; 082 // We know it's a control char, so only the last 2 chars are non-0 083 qbuf[4] = HC[value >> 4]; 084 qbuf[5] = HC[value & 0xF]; 085 return 6; 086 } 087 088 private static int _appendNamed(int esc, char[] qbuf) { 089 qbuf[1] = (char) esc; 090 return 2; 091 } 092 093}