ModifiedInputStream.java
/*
* Copyright (C) 2003-2013 eXo Platform SAS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.exoplatform.calendar.service;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by The eXo Platform SAS
* Author : vietnq
* vietnq@exoplatform.com
* Apr 12, 2013
*
*/
/**
* This class provides methods to modify an input stream before importing.
* Sometime, user's input stream is not standard conformed. We need to survive erroneous data
* See CAL-514, CAL-524
*/
public class ModifiedInputStream {
private static final int CR = 13;
private static final int LF = 10;
private static final int SPACE = 32;
private static final int COLON = 58;
private static final int SEMICOLON = 59;
private static final int MINUS = 45;
public static InputStream getIcsModifiedStream(InputStream in) throws IOException {
int prevChar = -1; //the last char read
int currentPos = 0; //current position that is read by input stream
int readChar;
BufferedInputStream bis = new BufferedInputStream(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((readChar = bis.read()) > -1) {
currentPos++;
if(prevChar == LF) { // if the read char is beginning of a line
// only test if the line begins with a property
if(readChar != SPACE) {
if(!beginWithAProperty(bis, readChar, currentPos)) {
baos.write(SPACE);
}
}
}
baos.write(readChar);
prevChar = readChar;
}
bis.close();
in.close();
return new ByteArrayInputStream(baos.toByteArray());
}
private static boolean beginWithAProperty(BufferedInputStream bis, int readChar, int currentPos) throws IOException {
if(!Character.isLetter((char)readChar)) {
return false;
}
if(readChar >= 'a') {
return false;
}
String testString = getPseudoProperty(bis, readChar, currentPos);
return isProperty(testString);
}
private static boolean isProperty(String str) throws IOException {
char lastChar = str.charAt(str.length() - 1);
// the property is followed by a COLON or a SEMICOLON
return lastChar == (char)COLON || lastChar == (char)SEMICOLON;
}
/*
* Gets the beginning of a line
* The method read the input stream at most 20 characters, until it meets a lower case character or
* the colon/semicolon or a non-letter character except MINUS.
*/
private static String getPseudoProperty(BufferedInputStream bis, int c, int currentPos) throws IOException {
bis.mark(currentPos); // mark the current position
StringBuilder sb = new StringBuilder(Character.toString((char)c));
int count = 0;
int tmpChar;
while(count < 20) {
tmpChar = bis.read();
count++;
if(tmpChar == CR || tmpChar == LF) {
break;
}
// stop when meeting the colon or semicolon
if(tmpChar == SEMICOLON || tmpChar == COLON) {
sb.append((char)tmpChar);
break;
}
// stop when meeting a non-letter character and different than MINUS
if(!Character.isLetter((char)tmpChar) && tmpChar != MINUS) {
break;
}
// stop when meeting a lower case char
if(tmpChar >= 'a') {
break;
}
}
bis.reset(); // return to the marked position
return sb.toString();
}
}