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 // %x22 / ; " quotation mark U+0022 028 // %x5C / ; \ reverse solidus U+005C 029 // %x2F / ; / solidus U+002F 030 031 // %x62 / ; b backspace U+0008 032 // %x74 / ; t tab U+0009 033 // %x6E / ; n line feed U+000A 034 // %x66 / ; f form feed U+000C 035 // %x72 / ; r carriage return U+000D 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 // %x22 / ; " quotation mark U+0022 081 // %x5C / ; \ reverse solidus U+005C 082 083 static String getObligatoryEscapeCode(char c) { 084 if (c < 32) 085 return ESCAPE_CODES[c]; 086 if (c == 0x22) 087 return "\\\""; 088 if (c == 0x5C) 089 return "\\/"; 090 091 return null; 092 } 093 094 static public String jsonEscapeString(String input) { 095 int length = input.length(); 096 int lenthWithLeeway = (int) (length * 1.1); 097 098 StringBuilder sb = new StringBuilder(lenthWithLeeway); 099 for (int i = 0; i < length; i++) { 100 final char c = input.charAt(i); 101 String escaped = getObligatoryEscapeCode(c); 102 if (escaped == null) 103 sb.append(c); 104 else { 105 sb.append(escaped); 106 } 107 } 108 109 return sb.toString(); 110 } 111 112}