/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> */ package org.olat.core.gui.render; import java.io.IOException; import java.io.Reader; import java.io.Writer; import org.apache.commons.lang.StringEscapeUtils; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.filter.impl.OWASPAntiSamyXSSFilter; /** * @author Felix Jost */ public class StringOutput extends Writer { private static final OLog log = Tracing.createLoggerFor(StringOutput.class); private final StringBuilder sb; /** * @param len */ public StringOutput(int len) { sb = new StringBuilder(len); } /** * */ public StringOutput() { sb = new StringBuilder(); } public char getLastChar() { return sb.length() > 0 ? sb.charAt(sb.length() - 1) : 0; } /** * @param val * @return Itself */ public StringOutput append(String val) { sb.append(val); return this; } public StringOutput append(String format, Object...args) { return appendFmt(format, args); } /** * * @param val The value to append * @param append If true append happens, if false not * @return Itself */ public StringOutput append(String val, boolean append) { if(append) { sb.append(val); } return this; } public StringOutput append(String valTrue, String valFalse, boolean val) { if(val) { sb.append(valTrue); } else { sb.append(valFalse); } return this; } public StringOutput ifCond(boolean cond) { if (cond) return this; return new StringOutput(); } public StringOutput appendFmt(String format, Object...params) { if(params.length == 0) { sb.append(format); } else { String v = String.format(format, params); sb.append(v); } return this; } /** * @param val * @return Itself */ public StringOutput append(boolean val) { sb.append(val); return this; } /** * @param i * @return Itself */ public StringOutput append(int i) { sb.append(i); return this; } public StringOutput append(double d) { sb.append(Double.toString(d)); return this; } /** * @param stringOutput * @return Itself */ public StringOutput append(StringOutput stringOutput) { sb.append(stringOutput.sb); return this; } @Override public void write(char[] cbuf, int off, int len) throws IOException { sb.append(cbuf, off, len); } /** * @param sMin * @return Itself */ public StringOutput append(long val) { sb.append(val); return this; } /** * @param buffer * @return Itself */ public StringOutput append(StringBuilder buffer) { sb.append(buffer); return this; } /** * @param buffer * @return Itself */ public StringOutput appendScanned(String str) { sb.append(new OWASPAntiSamyXSSFilter().filter(str)); return this; } /** * @param buffer * @return Itself */ public StringOutput appendHtmlEscaped(String str) { try { StringEscapeUtils.escapeHtml(this, str); } catch (IOException e) { log.error("Error escaping HTML", e); } return this; } public void ensureCapacity(int minimumCapacity) { sb.ensureCapacity(minimumCapacity); } public int capacity() { return sb.capacity(); } public void setLength(int newLength) { sb.setLength(newLength); } /** * @return The length of the string output */ public int length() { return sb.length(); } public Reader getReader() { return new StringOutputReader(); } @Override public void flush() throws IOException { // } @Override public void close() throws IOException { // } /** * @see java.lang.Object#toString() */ @Override public String toString() { return sb.toString(); } private class StringOutputReader extends Reader { private int length; private int next = 0; private int mark = 0; /** * Creates a new string reader. * * @param s String providing the character stream. */ public StringOutputReader() { this.length = sb.length(); } /** * Reads a single character. * * @return The character read, or -1 if the end of the stream has been * reached * * @exception IOException If an I/O error occurs */ public int read() throws IOException { synchronized (lock) { if (next >= length) return -1; char[] dst = new char[1]; sb.getChars(next++, next, dst, 0); return dst[0]; } } public int read(char cbuf[], int off, int len) throws IOException { synchronized (lock) { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (next >= length) return -1; int n = Math.min(length - next, len); sb.getChars(next, next + n, cbuf, off); next += n; return n; } } /** * Skips the specified number of characters in the stream. Returns * the number of characters that were skipped. * * <p>The <code>ns</code> parameter may be negative, even though the * <code>skip</code> method of the {@link Reader} superclass throws * an exception in this case. Negative values of <code>ns</code> cause the * stream to skip backwards. Negative return values indicate a skip * backwards. It is not possible to skip backwards past the beginning of * the string. * * <p>If the entire string has been read or skipped, then this method has * no effect and always returns 0. * * @exception IOException If an I/O error occurs */ public long skip(long ns) throws IOException { synchronized (lock) { if (next >= length) return 0; // Bound skip by beginning and end of the source long n = Math.min(length - next, ns); n = Math.max(-next, n); next += n; return n; } } public boolean ready() throws IOException { synchronized (lock) { return true; } } public boolean markSupported() { return true; } public void mark(int readAheadLimit) throws IOException { if (readAheadLimit < 0) { throw new IllegalArgumentException("Read-ahead limit < 0"); } synchronized (lock) { mark = next; } } public void reset() throws IOException { synchronized (lock) { next = mark; } } public void close() { // } } }