src/net/fortuna/ical4j/data/UnfoldingReader.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

michael@0 1 /**
michael@0 2 * Copyright (c) 2012, Ben Fortuna
michael@0 3 * All rights reserved.
michael@0 4 *
michael@0 5 * Redistribution and use in source and binary forms, with or without
michael@0 6 * modification, are permitted provided that the following conditions
michael@0 7 * are met:
michael@0 8 *
michael@0 9 * o Redistributions of source code must retain the above copyright
michael@0 10 * notice, this list of conditions and the following disclaimer.
michael@0 11 *
michael@0 12 * o Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in the
michael@0 14 * documentation and/or other materials provided with the distribution.
michael@0 15 *
michael@0 16 * o Neither the name of Ben Fortuna nor the names of any other contributors
michael@0 17 * may be used to endorse or promote products derived from this software
michael@0 18 * without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
michael@0 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
michael@0 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
michael@0 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
michael@0 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
michael@0 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
michael@0 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
michael@0 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32 package net.fortuna.ical4j.data;
michael@0 33
michael@0 34 import java.io.IOException;
michael@0 35 import java.io.PushbackReader;
michael@0 36 import java.io.Reader;
michael@0 37 import java.util.Arrays;
michael@0 38
michael@0 39 import net.fortuna.ical4j.util.CompatibilityHints;
michael@0 40
michael@0 41 import org.apache.commons.logging.Log;
michael@0 42 import org.apache.commons.logging.LogFactory;
michael@0 43
michael@0 44 /**
michael@0 45 * <pre>
michael@0 46 * $Id$ [06-Apr-2004]
michael@0 47 * </pre>
michael@0 48 *
michael@0 49 * A reader which performs iCalendar unfolding as it reads. Note that unfolding rules may be "relaxed" to allow
michael@0 50 * unfolding of non-conformant *.ics files. By specifying the system property "ical4j.unfolding.relaxed=true" iCalendar
michael@0 51 * files created with Mozilla Calendar/Sunbird may be correctly unfolded.
michael@0 52 *
michael@0 53 * To wrap this reader with a {@link java.io.BufferedReader} you must ensure you specify an identical buffer size
michael@0 54 * to that used in the {@link java.io.BufferedReader}.
michael@0 55 *
michael@0 56 * @author Ben Fortuna
michael@0 57 */
michael@0 58 public class UnfoldingReader extends PushbackReader {
michael@0 59
michael@0 60 private Log log = LogFactory.getLog(UnfoldingReader.class);
michael@0 61
michael@0 62 /**
michael@0 63 * The pattern used to identify a fold in an iCalendar data stream.
michael@0 64 */
michael@0 65 private static final char[] DEFAULT_FOLD_PATTERN_1 = { '\r', '\n', ' ' };
michael@0 66
michael@0 67 /**
michael@0 68 * The pattern used to identify a fold in Microsoft Outlook 2007.
michael@0 69 */
michael@0 70 private static final char[] DEFAULT_FOLD_PATTERN_2 = { '\r', '\n', '\t' };
michael@0 71
michael@0 72 /**
michael@0 73 * The pattern used to identify a fold in Mozilla Calendar/Sunbird and KOrganizer.
michael@0 74 */
michael@0 75 private static final char[] RELAXED_FOLD_PATTERN_1 = { '\n', ' ' };
michael@0 76
michael@0 77 /**
michael@0 78 * The pattern used to identify a fold in Microsoft Outlook 2007.
michael@0 79 */
michael@0 80 private static final char[] RELAXED_FOLD_PATTERN_2 = { '\n', '\t' };
michael@0 81
michael@0 82 private char[][] patterns;
michael@0 83
michael@0 84 private char[][] buffers;
michael@0 85
michael@0 86 private int linesUnfolded;
michael@0 87
michael@0 88 private int maxPatternLength = 0;
michael@0 89
michael@0 90 /**
michael@0 91 * Creates a new unfolding reader instance. Relaxed unfolding flag is read from system property.
michael@0 92 * @param in the reader to unfold from
michael@0 93 */
michael@0 94 public UnfoldingReader(final Reader in) {
michael@0 95 this(in, DEFAULT_FOLD_PATTERN_1.length, CompatibilityHints
michael@0 96 .isHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING));
michael@0 97 }
michael@0 98
michael@0 99 /**
michael@0 100 * @param in reader source for data
michael@0 101 * @param size the buffer size
michael@0 102 */
michael@0 103 public UnfoldingReader(final Reader in, int size) {
michael@0 104 this(in, size, CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING));
michael@0 105 }
michael@0 106
michael@0 107 /**
michael@0 108 * @param in reader source for data
michael@0 109 * @param relaxed indicates whether relaxed unfolding is enabled
michael@0 110 */
michael@0 111 public UnfoldingReader(final Reader in, boolean relaxed) {
michael@0 112 this(in, DEFAULT_FOLD_PATTERN_1.length, relaxed);
michael@0 113 }
michael@0 114
michael@0 115 /**
michael@0 116 * Creates a new unfolding reader instance.
michael@0 117 * @param in a reader to read from
michael@0 118 * @param size the buffer size
michael@0 119 * @param relaxed specifies whether unfolding is relaxed
michael@0 120 */
michael@0 121 public UnfoldingReader(final Reader in, int size, final boolean relaxed) {
michael@0 122 super(in, size);
michael@0 123 if (relaxed) {
michael@0 124 patterns = new char[4][];
michael@0 125 patterns[0] = DEFAULT_FOLD_PATTERN_1;
michael@0 126 patterns[1] = DEFAULT_FOLD_PATTERN_2;
michael@0 127 patterns[2] = RELAXED_FOLD_PATTERN_1;
michael@0 128 patterns[3] = RELAXED_FOLD_PATTERN_2;
michael@0 129 }
michael@0 130 else {
michael@0 131 patterns = new char[2][];
michael@0 132 patterns[0] = DEFAULT_FOLD_PATTERN_1;
michael@0 133 patterns[1] = DEFAULT_FOLD_PATTERN_2;
michael@0 134 }
michael@0 135 buffers = new char[patterns.length][];
michael@0 136 for (int i = 0; i < patterns.length; i++) {
michael@0 137 buffers[i] = new char[patterns[i].length];
michael@0 138 maxPatternLength = Math.max(maxPatternLength, patterns[i].length);
michael@0 139 }
michael@0 140 }
michael@0 141
michael@0 142 /**
michael@0 143 * @return number of lines unfolded so far while reading
michael@0 144 */
michael@0 145 public final int getLinesUnfolded() {
michael@0 146 return linesUnfolded;
michael@0 147 }
michael@0 148
michael@0 149 /**
michael@0 150 * {@inheritDoc}
michael@0 151 */
michael@0 152 public final int read() throws IOException {
michael@0 153 final int c = super.read();
michael@0 154 boolean doUnfold = false;
michael@0 155 for (int i = 0; i < patterns.length; i++) {
michael@0 156 if (c == patterns[i][0]) {
michael@0 157 doUnfold = true;
michael@0 158 break;
michael@0 159 }
michael@0 160 }
michael@0 161 if (!doUnfold) {
michael@0 162 return c;
michael@0 163 }
michael@0 164 else {
michael@0 165 unread(c);
michael@0 166 }
michael@0 167
michael@0 168 unfold();
michael@0 169
michael@0 170 return super.read();
michael@0 171 }
michael@0 172
michael@0 173 /**
michael@0 174 * {@inheritDoc}
michael@0 175 */
michael@0 176 public int read(final char[] cbuf, final int off, final int len) throws IOException {
michael@0 177 final int read = super.read(cbuf, off, len);
michael@0 178 boolean doUnfold = false;
michael@0 179 for (int i = 0; i < patterns.length; i++) {
michael@0 180 if (read > 0 && cbuf[0] == patterns[i][0]) {
michael@0 181 doUnfold = true;
michael@0 182 break;
michael@0 183 }
michael@0 184 else {
michael@0 185 for (int j = 0; j < read; j++) {
michael@0 186 if (cbuf[j] == patterns[i][0]) {
michael@0 187 unread(cbuf, j, read - j);
michael@0 188 return j;
michael@0 189 }
michael@0 190 }
michael@0 191 }
michael@0 192 }
michael@0 193 if (!doUnfold) {
michael@0 194 return read;
michael@0 195 }
michael@0 196 else {
michael@0 197 unread(cbuf, off, read);
michael@0 198 }
michael@0 199
michael@0 200 unfold();
michael@0 201
michael@0 202 return super.read(cbuf, off, maxPatternLength);
michael@0 203 }
michael@0 204
michael@0 205 private void unfold() throws IOException {
michael@0 206 // need to loop since one line fold might be directly followed by another
michael@0 207 boolean didUnfold;
michael@0 208 do {
michael@0 209 didUnfold = false;
michael@0 210
michael@0 211 for (int i = 0; i < buffers.length; i++) {
michael@0 212 int read = 0;
michael@0 213 while (read < buffers[i].length) {
michael@0 214 final int partialRead = super.read(buffers[i], read, buffers[i].length - read);
michael@0 215 if (partialRead < 0) {
michael@0 216 break;
michael@0 217 }
michael@0 218 read += partialRead;
michael@0 219 }
michael@0 220 if (read > 0) {
michael@0 221 if (!Arrays.equals(patterns[i], buffers[i])) {
michael@0 222 unread(buffers[i], 0, read);
michael@0 223 }
michael@0 224 else {
michael@0 225 if (log.isTraceEnabled()) {
michael@0 226 log.trace("Unfolding...");
michael@0 227 }
michael@0 228 linesUnfolded++;
michael@0 229 didUnfold = true;
michael@0 230 }
michael@0 231 }
michael@0 232 // else {
michael@0 233 // return read;
michael@0 234 // }
michael@0 235 }
michael@0 236 }
michael@0 237 while (didUnfold);
michael@0 238 }
michael@0 239 }

mercurial