001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2023, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.core.encoder; 016 017public class JsonEscapeUtil { 018 019 protected final static char[] HEXADECIMALS_TABLE = "0123456789ABCDEF".toCharArray(); 020 021 static final int ESCAPE_CODES_COUNT = 32; 022 023 static final String[] ESCAPE_CODES = new String[ESCAPE_CODES_COUNT]; 024 025 // From RFC-8259 page 5 026 027 // " quotation mark U+0022 -- escaped as \" 028 // \ reverse solidus U+005C -- escaped as \\ 029 // / solidus U+002F -- escaped as \/ 030 031 // backspace U+0008 -- escaped as \b 032 // tab U+0009 -- escaped as \t 033 // line feed U+000A -- escaped as \n 034 // form feed U+000C -- escaped as \f 035 // carriage return U+000D -- escaped as \r 036 037 static { 038 for (char c = 0; c < ESCAPE_CODES_COUNT; c++) { 039 040 switch (c) { 041 case 0x08: 042 ESCAPE_CODES[c] = "\\b"; 043 break; 044 case 0x09: 045 ESCAPE_CODES[c] = "\\t"; 046 break; 047 case 0x0A: 048 ESCAPE_CODES[c] = "\\n"; 049 break; 050 case 0x0C: 051 ESCAPE_CODES[c] = "\\f"; 052 break; 053 case 0x0D: 054 ESCAPE_CODES[c] = "\\r"; 055 break; 056 default: 057 ESCAPE_CODES[c] = _computeEscapeCodeBelowASCII32(c); 058 } 059 } 060 } 061 062 // this method should not be called by methods except the static initializer 063 private static String _computeEscapeCodeBelowASCII32(char c) { 064 if (c > 32) { 065 throw new IllegalArgumentException("input must be less than 32"); 066 } 067 068 StringBuilder sb = new StringBuilder(6); 069 sb.append("\\u00"); 070 071 int highPart = c >> 4; 072 sb.append(HEXADECIMALS_TABLE[highPart]); 073 074 int lowPart = c & 0x0F; 075 sb.append(HEXADECIMALS_TABLE[lowPart]); 076 077 return sb.toString(); 078 } 079 080 // " quotation mark U+0022 -- escaped as \" 081 // \ reverse solidus U+005C -- escaped as \\ 082 // / solidus U+002F -- escaped as \/ 083 084 static String getObligatoryEscapeCode(char c) { 085 if (c < 32) 086 return ESCAPE_CODES[c]; 087 if (c == 0x22) 088 return "\\\""; 089 if (c == 0x2F) 090 return "\\/"; 091 if (c == 0x5C) 092 return "\\\\"; 093 094 return null; 095 } 096 097 static public String jsonEscapeString(String input) { 098 int length = input.length(); 099 int lenthWithLeeway = (int) (length * 1.1); 100 101 StringBuilder sb = new StringBuilder(lenthWithLeeway); 102 for (int i = 0; i < length; i++) { 103 final char c = input.charAt(i); 104 String escaped = getObligatoryEscapeCode(c); 105 if (escaped == null) 106 sb.append(c); 107 else { 108 sb.append(escaped); 109 } 110 } 111 112 return sb.toString(); 113 } 114 115}