/* ****************************************************************************** * Copyright (c) 2006-2016 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ /** * */ package org.xmind.core.net.internal; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /** * Invisible characters are encoded using * <a href="https://en.wikipedia.org/wiki/Quoted-printable">Quoted-Printable * codec</a>. * * @author Frank Shaka * @since 3.6.51 */ public class LoggingOutputStream extends FilterOutputStream { private static final byte MIN_VISIBLE_CHAR = (byte) 32; private static final byte MAX_VISIBLE_CHAR = (byte) 126; private static final byte PREFIX = (byte) '='; private static final byte LF = (byte) '\n'; private static final byte CR = (byte) '\r'; private static final byte START1 = (byte) '0'; private static final byte START2 = (byte) ('A' - 10); private byte[] buffer; /** * @param out */ public LoggingOutputStream(OutputStream out) { super(out); this.buffer = new byte[1024]; } private int quote(byte[] b, int off, int len) { int buffered = 0; int n; for (int i = 0; i < len; i++) { n = quote(b[i], buffered); buffered += n; } return buffered; } private int quote(byte b, int bufferOffset) { if (b != LF && b != CR && (b == PREFIX || b < MIN_VISIBLE_CHAR || b > MAX_VISIBLE_CHAR)) { ensureBufferSize(bufferOffset + 2); buffer[bufferOffset] = PREFIX; buffer[bufferOffset + 1] = toHex((b & 0xF0) >> 4); buffer[bufferOffset + 2] = toHex(b & 0x0F); return 3; } else { ensureBufferSize(bufferOffset); buffer[bufferOffset] = b; return 1; } } private static final byte toHex(int x) { if (x < 10) { return (byte) (START1 + x); } return (byte) (START2 + x); } /** * @param expectedSize */ private void ensureBufferSize(int expectedSize) { if (expectedSize >= buffer.length) { byte[] newBuffer = new byte[(int) (buffer.length * 1.4)]; System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); buffer = newBuffer; } } /* * (non-Javadoc) * @see java.io.FilterOutputStream#write(byte[]) */ @Override public void write(byte[] b) throws IOException { int n = quote(b, 0, b.length); try { out.write(buffer, 0, n); out.flush(); } catch (IOException e) { } } /* * (non-Javadoc) * @see java.io.FilterOutputStream#write(byte[], int, int) */ @Override public void write(byte[] b, int off, int len) throws IOException { int n = quote(b, off, len); try { out.write(buffer, 0, n); out.flush(); } catch (IOException e) { } } /* * (non-Javadoc) * @see java.io.FilterOutputStream#write(int) */ @Override public void write(int b) throws IOException { int n = quote((byte) b, 0); try { out.write(buffer, 0, n); out.flush(); } catch (IOException e) { } } }