001 package ezvcard.io; 002 003 import java.io.IOException; 004 import java.io.Writer; 005 006 /* 007 Copyright (c) 2012, Michael Angstadt 008 All rights reserved. 009 010 Redistribution and use in source and binary forms, with or without 011 modification, are permitted provided that the following conditions are met: 012 013 1. Redistributions of source code must retain the above copyright notice, this 014 list of conditions and the following disclaimer. 015 2. Redistributions in binary form must reproduce the above copyright notice, 016 this list of conditions and the following disclaimer in the documentation 017 and/or other materials provided with the distribution. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 026 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 030 The views and conclusions contained in the software and documentation are those 031 of the authors and should not be interpreted as representing official policies, 032 either expressed or implied, of the FreeBSD Project. 033 */ 034 035 /** 036 * Automatically folds lines as they are written. 037 * @author Michael Angstadt 038 */ 039 public class FoldedLineWriter extends Writer { 040 private int curLineLength = 0; 041 private int lineLength; 042 private String indent; 043 private String newline; 044 private final Writer writer; 045 046 /** 047 * @param writer the writer object to wrap 048 * @param lineLength the maximum length a line can be before it is folded 049 * (excluding the newline) 050 * @param indent the string to prepend to each folded line (e.g. a single 051 * space character) 052 * @param newline the newline sequence to use (e.g. "\r\n") 053 * @throws IllegalArgumentException if the line length is less than or equal 054 * to zero 055 * @throws IllegalArgumentException if the length of the indent string is 056 * greater than the max line length 057 */ 058 public FoldedLineWriter(Writer writer, int lineLength, String indent, String newline) { 059 setLineLength(lineLength); 060 setIndent(indent); 061 this.writer = writer; 062 this.newline = newline; 063 } 064 065 /** 066 * Writes a string of text, followed by a newline. 067 * @param str the text to write 068 * @throws IOException if there's a problem writing to the output stream 069 */ 070 public void writeln(String str) throws IOException { 071 write(str); 072 write(newline); 073 } 074 075 @Override 076 public void write(char buf[], int start, int end) throws IOException { 077 write(buf, start, end, lineLength, indent); 078 } 079 080 /** 081 * Writes a portion of an array of characters. 082 * @param buf the array of characters 083 * @param start the offset from which to start writing characters 084 * @param end the number of characters to write 085 * @param lineLength the maximum length a line can be before it is folded 086 * (excluding the newline) 087 * @param indent the indent string to use (e.g. a single space character) 088 * @throws IOException if there's a problem writing to the output stream 089 */ 090 public void write(char buf[], int start, int end, int lineLength, String indent) throws IOException { 091 for (int i = start; i < end; i++) { 092 char c = buf[i]; 093 if (c == '\n') { 094 writer.write(buf, start, i - start + 1); 095 curLineLength = 0; 096 start = i + 1; 097 } else if (c == '\r') { 098 if (i == end - 1 || buf[i + 1] != '\n') { 099 writer.write(buf, start, i - start + 1); 100 curLineLength = 0; 101 start = i + 1; 102 } else { 103 curLineLength++; 104 } 105 } else if (curLineLength >= lineLength) { 106 //if the last characters on the line are whitespace, then exceed the max line length in order to include the whitespace on the same line 107 //otherwise it will be lost because it will merge with the padding on the next line 108 if (Character.isWhitespace(c)) { 109 while (Character.isWhitespace(c) && i < end - 1) { 110 i++; 111 c = buf[i]; 112 } 113 if (i == end - 1) { 114 //the rest of the char array is whitespace, so leave the loop 115 break; 116 } 117 } 118 119 writer.write(buf, start, i - start); 120 String s = newline + indent; 121 writer.write(s.toCharArray(), 0, s.length()); 122 start = i; 123 curLineLength = indent.length() + 1; 124 } else { 125 curLineLength++; 126 } 127 } 128 writer.write(buf, start, end - start); 129 } 130 131 @Override 132 public void close() throws IOException { 133 writer.close(); 134 } 135 136 @Override 137 public void flush() throws IOException { 138 writer.flush(); 139 } 140 141 /** 142 * Gets the maximum length a line can be before it is folded (excluding the 143 * newline). 144 * @return the line length 145 */ 146 public int getLineLength() { 147 return lineLength; 148 } 149 150 /** 151 * Sets the maximum length a line can be before it is folded (excluding the 152 * newline). 153 * @param lineLength the line length 154 * @throws IllegalArgumentException if the line length is less than or equal 155 * to zero 156 */ 157 public void setLineLength(int lineLength) { 158 if (lineLength <= 0) { 159 throw new IllegalArgumentException("Line length must be greater than 0."); 160 } 161 this.lineLength = lineLength; 162 } 163 164 /** 165 * Gets the string that is prepended to each folded line. 166 * @return the indent string 167 */ 168 public String getIndent() { 169 return indent; 170 } 171 172 /** 173 * Sets the string that is prepended to each folded line. 174 * @param indent the indent string (e.g. a single space character) 175 * @throws IllegalArgumentException if the length of the indent string is 176 * greater than the max line length 177 */ 178 public void setIndent(String indent) { 179 if (indent.length() >= lineLength) { 180 throw new IllegalArgumentException("The length of the indent string must be less than the max line length."); 181 } 182 this.indent = indent; 183 } 184 185 /** 186 * Gets the newline sequence that is used to separate lines. 187 * @return the newline sequence 188 */ 189 public String getNewline() { 190 return newline; 191 } 192 193 /** 194 * Sets the newline sequence that is used to separate lines 195 * @param newline the newline sequence 196 */ 197 public void setNewline(String newline) { 198 this.newline = newline; 199 } 200 }