001/* 002 * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html.markup; 027 028import java.io.IOException; 029import java.io.Writer; 030 031import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 032 033/** 034 * A representation of HTML entities. 035 */ 036public class Entity extends Content { 037 public static final Entity LESS_THAN = new Entity("<"); 038 public static final Entity GREATER_THAN = new Entity(">"); 039 public static final Entity AMPERSAND = new Entity("&"); 040 public static final Entity NO_BREAK_SPACE = new Entity(" "); 041 042 public final String text; 043 044 /** 045 * Creates an entity with a given name or numeric value. 046 * 047 * @param name the name, or numeric value 048 * @return the entity 049 */ 050 public static Entity of(CharSequence name) { 051 return new Entity("&" + name + ";"); 052 } 053 054 private Entity(String text) { 055 this.text = text; 056 } 057 058 @Override 059 public boolean write(Writer writer, String newline, boolean atNewline) 060 throws IOException { 061 writer.write(text); 062 return false; 063 } 064 065 @Override 066 public boolean isEmpty() { 067 return false; 068 } 069 070 @Override 071 public int charCount() { 072 return 1; 073 } 074 075 /** 076 * Escapes the special HTML characters in a given string using the appropriate 077 * entities. 078 * 079 * @param s the string to escape 080 * @return the string with all of the HTML characters escaped 081 */ 082 static String escapeHtmlChars(CharSequence s) { 083 // Convert to string as CharSequence implementations can be slow - see 084 // JDK-8263321 085 String str = s.toString(); 086 for (int i = 0; i < str.length(); i++) { 087 char ch = str.charAt(i); 088 switch (ch) { 089 // only start building a new string if we need to 090 case '<', '>', '&' -> { 091 StringBuilder sb = new StringBuilder(str.substring(0, i)); 092 escapeHtmlChars(str, i, sb); 093 return sb.toString(); 094 } 095 } 096 } 097 return str; 098 } 099 100 /** 101 * Escapes the special HTML characters in a given string using the appropriate 102 * entities, appending the results into a string builder. 103 * 104 * @param s the string 105 * @param sb the string builder 106 */ 107 static void escapeHtmlChars(CharSequence s, StringBuilder sb) { 108 escapeHtmlChars(s.toString(), 0, sb); 109 } 110 111 private static void escapeHtmlChars(String s, int start, StringBuilder sb) { 112 for (int i = start; i < s.length(); i++) { 113 char ch = s.charAt(i); 114 switch (ch) { 115 case '<' -> sb.append(Entity.LESS_THAN.text); 116 case '>' -> sb.append(Entity.GREATER_THAN.text); 117 case '&' -> sb.append(Entity.AMPERSAND.text); 118 default -> sb.append(ch); 119 } 120 } 121 } 122 123}