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.

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

mercurial