18413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe/* 28413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Copyright (C) 2015 The Android Open Source Project 38413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * 48413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 58413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * you may not use this file except in compliance with the License. 68413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * You may obtain a copy of the License at 78413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * 88413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 98413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * 108413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Unless required by applicable law or agreed to in writing, software 118413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 128413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * See the License for the specific language governing permissions and 148413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * limitations under the License. 158413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 168413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 178413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampepackage com.android.internal.util; 188413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 198413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampeimport java.io.PrintWriter; 208413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampeimport java.io.Writer; 218413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampeimport java.util.Arrays; 228413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 238413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe/** 248413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * A writer that breaks up its output into chunks before writing to its out writer, 258413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * and which is linebreak aware, i.e., chunks will created along line breaks, if 268413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * possible. 278413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * 288413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Note: this class is not thread-safe. 298413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 308413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampepublic class LineBreakBufferedWriter extends PrintWriter { 318413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 328413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 338413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * A buffer to collect data until the buffer size is reached. 348413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * 358413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Note: we manage a char[] ourselves to avoid an allocation when printing to the 368413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * out writer. Otherwise a StringBuilder would have been simpler to use. 378413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 388413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private char[] buffer; 398413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 408413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 418413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * The index of the first free element in the buffer. 428413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 438413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private int bufferIndex; 448413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 458413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 468413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * The chunk size (=maximum buffer size) to use for this writer. 478413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 488413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private final int bufferSize; 498413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 508413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 518413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 528413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Index of the last newline character discovered in the buffer. The writer will try 538413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * to split there. 548413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 558413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private int lastNewline = -1; 568413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 578413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 588413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * The line separator for println(). 598413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 608413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private final String lineSeparator; 618413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 628413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 638413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Create a new linebreak-aware buffered writer with the given output and buffer 648413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * size. The initial capacity will be a default value. 658413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param out The writer to write to. 668413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param bufferSize The maximum buffer size. 678413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 688413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public LineBreakBufferedWriter(Writer out, int bufferSize) { 698413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe this(out, bufferSize, 16); // 16 is the default size of a StringBuilder buffer. 708413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 718413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 728413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 738413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Create a new linebreak-aware buffered writer with the given output, buffer 748413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * size and initial capacity. 758413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param out The writer to write to. 768413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param bufferSize The maximum buffer size. 778413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param initialCapacity The initial capacity of the internal buffer. 788413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 798413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public LineBreakBufferedWriter(Writer out, int bufferSize, int initialCapacity) { 808413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe super(out); 818413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe this.buffer = new char[Math.min(initialCapacity, bufferSize)]; 828413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe this.bufferIndex = 0; 838413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe this.bufferSize = bufferSize; 848413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe this.lineSeparator = System.getProperty("line.separator"); 858413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 868413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 878413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 888413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Flush the current buffer. This will ignore line breaks. 898413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 908413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe @Override 918413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public void flush() { 928413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(bufferIndex); 938413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 948413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe super.flush(); 958413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 968413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 978413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe @Override 988413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public void write(int c) { 99f72cc9437b7592980003050c492526c660dc5b14Andreas Gampe if (bufferIndex < buffer.length) { 1008413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe buffer[bufferIndex] = (char)c; 1018413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex++; 1028413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if ((char)c == '\n') { 1038413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = bufferIndex; 1048413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1058413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 1068413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // This should be an uncommon case, we mostly expect char[] and String. So 1078413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // let the chunking be handled by the char[] case. 1088413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe write(new char[] { (char)c }, 0 ,1); 1098413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1108413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1118413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1128413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe @Override 1138413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public void println() { 1148413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe write(lineSeparator); 1158413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1168413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1178413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe @Override 1188413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public void write(char[] buf, int off, int len) { 1198413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe while (bufferIndex + len > bufferSize) { 1208413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Find the next newline in the buffer, see if that's below the limit. 1218413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Repeat. 1228413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int nextNewLine = -1; 1238413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int maxLength = bufferSize - bufferIndex; 1248413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe for (int i = 0; i < maxLength; i++) { 1258413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (buf[off + i] == '\n') { 1268413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (bufferIndex + i < bufferSize) { 1278413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe nextNewLine = i; 1288413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 1298413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe break; 1308413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1318413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1328413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1338413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1348413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (nextNewLine != -1) { 1358413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // We can add some more data. 1368413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(buf, off, nextNewLine); 1378413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(bufferIndex); 1388413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 1398413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = -1; 1408413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe off += nextNewLine + 1; 1418413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe len -= nextNewLine + 1; 1428413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else if (lastNewline != -1) { 1438413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Use the last newline. 1448413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(lastNewline); 1458413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe removeFromBuffer(lastNewline + 1); 1468413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = -1; 1478413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 1488413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // OK, there was no newline, break at a full buffer. 1498413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int rest = bufferSize - bufferIndex; 1508413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(buf, off, rest); 1518413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(bufferIndex); 1528413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 1538413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe off += rest; 1548413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe len -= rest; 1558413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1568413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1578413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1588413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Add to the buffer, this will fit. 1598413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (len > 0) { 1608413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Add the chars, find the last newline. 1618413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(buf, off, len); 1628413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe for (int i = len - 1; i >= 0; i--) { 1638413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (buf[off + i] == '\n') { 1648413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = bufferIndex - len + i; 1658413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe break; 1668413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1678413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1688413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1698413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1708413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1718413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe @Override 1728413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe public void write(String s, int off, int len) { 1738413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe while (bufferIndex + len > bufferSize) { 1748413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Find the next newline in the buffer, see if that's below the limit. 1758413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Repeat. 1768413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int nextNewLine = -1; 1778413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int maxLength = bufferSize - bufferIndex; 1788413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe for (int i = 0; i < maxLength; i++) { 1798413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (s.charAt(off + i) == '\n') { 1808413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (bufferIndex + i < bufferSize) { 1818413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe nextNewLine = i; 1828413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 1838413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe break; 1848413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1858413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1868413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 1878413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 1888413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (nextNewLine != -1) { 1898413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // We can add some more data. 1908413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(s, off, nextNewLine); 1918413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(bufferIndex); 1928413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 1938413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = -1; 1948413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe off += nextNewLine + 1; 1958413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe len -= nextNewLine + 1; 1968413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else if (lastNewline != -1) { 1978413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Use the last newline. 1988413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(lastNewline); 1998413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe removeFromBuffer(lastNewline + 1); 2008413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = -1; 2018413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 2028413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // OK, there was no newline, break at a full buffer. 2038413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int rest = bufferSize - bufferIndex; 2048413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(s, off, rest); 2058413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe writeBuffer(bufferIndex); 2068413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 2078413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe off += rest; 2088413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe len -= rest; 2098413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2108413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2118413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2128413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Add to the buffer, this will fit. 2138413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (len > 0) { 2148413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe // Add the chars, find the last newline. 2158413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe appendToBuffer(s, off, len); 2168413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe for (int i = len - 1; i >= 0; i--) { 2178413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (s.charAt(off + i) == '\n') { 2188413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe lastNewline = bufferIndex - len + i; 2198413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe break; 2208413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2218413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2228413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2238413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2248413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2258413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 2268413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Append the characters to the buffer. This will potentially resize the buffer, 2278413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * and move the index along. 2288413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param buf The char[] containing the data. 2298413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param off The start index to copy from. 2308413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param len The number of characters to copy. 2318413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 2328413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private void appendToBuffer(char[] buf, int off, int len) { 2338413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (bufferIndex + len > buffer.length) { 2348413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe ensureCapacity(bufferIndex + len); 2358413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2368413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe System.arraycopy(buf, off, buffer, bufferIndex, len); 2378413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex += len; 2388413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2398413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2408413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 2418413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Append the characters from the given string to the buffer. This will potentially 2428413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * resize the buffer, and move the index along. 2438413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param s The string supplying the characters. 2448413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param off The start index to copy from. 2458413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param len The number of characters to copy. 2468413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 2478413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private void appendToBuffer(String s, int off, int len) { 2488413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (bufferIndex + len > buffer.length) { 2498413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe ensureCapacity(bufferIndex + len); 2508413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2518413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe s.getChars(off, off + len, buffer, bufferIndex); 2528413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex += len; 2538413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2548413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2558413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 2568413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Resize the buffer. We use the usual double-the-size plus constant scheme for 2578413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * amortized O(1) insert. Note: we expect small buffers, so this won't check for 2588413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * overflow. 2598413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param capacity The size to be ensured. 2608413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 2618413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private void ensureCapacity(int capacity) { 2628413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int newSize = buffer.length * 2 + 2; 2638413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (newSize < capacity) { 2648413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe newSize = capacity; 2658413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2668413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe buffer = Arrays.copyOf(buffer, newSize); 2678413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2688413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2698413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 2708413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Remove the characters up to (and excluding) index i from the buffer. This will 2718413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * not resize the buffer, but will update bufferIndex. 2728413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param i The number of characters to remove from the front. 2738413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 2748413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private void removeFromBuffer(int i) { 2758413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe int rest = bufferIndex - i; 2768413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (rest > 0) { 2778413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe System.arraycopy(buffer, bufferIndex - rest, buffer, 0, rest); 2788413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = rest; 2798413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } else { 2808413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe bufferIndex = 0; 2818413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2828413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2838413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe 2848413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe /** 2858413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * Helper method, write the given part of the buffer, [start,length), to the output. 2868413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe * @param length The number of characters to flush. 2878413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe */ 2888413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe private void writeBuffer(int length) { 2898413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe if (length > 0) { 2908413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe super.write(buffer, 0, length); 2918413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2928413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe } 2938413db8c36f4ba5979cdc2b1c3e1429e6ba34d6aAndreas Gampe} 294