client/ftpd/src/se/lu/thep/coreftpd/common/DataInputStreamWithReadLine.java

Code
Comments
Other
Rev Date Author Line
741 10 Oct 06 olle 1 /*
1652 22 May 07 gregory 2  $Id$
741 10 Oct 06 olle 3
1916 31 Aug 07 jari 4  Copyright (C) 2006 Olle Mansson
1916 31 Aug 07 jari 5  Copyright (C) 2007 Gregory Vincic
741 10 Oct 06 olle 6
1652 22 May 07 gregory 7  This file is part of Proteios.
1652 22 May 07 gregory 8  Available at http://www.proteios.org/
741 10 Oct 06 olle 9
1652 22 May 07 gregory 10  Proteios is free software; you can redistribute it and/or modify it
1652 22 May 07 gregory 11  under the terms of the GNU General Public License as published by
1652 22 May 07 gregory 12  the Free Software Foundation; either version 2 of the License, or
1652 22 May 07 gregory 13  (at your option) any later version.
741 10 Oct 06 olle 14
1652 22 May 07 gregory 15  Proteios is distributed in the hope that it will be useful, but
1652 22 May 07 gregory 16  WITHOUT ANY WARRANTY; without even the implied warranty of
1652 22 May 07 gregory 17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1652 22 May 07 gregory 18  General Public License for more details.
741 10 Oct 06 olle 19
1652 22 May 07 gregory 20  You should have received a copy of the GNU General Public License
1652 22 May 07 gregory 21  along with this program; if not, write to the Free Software
1652 22 May 07 gregory 22  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1652 22 May 07 gregory 23  02111-1307, USA.
1652 22 May 07 gregory 24  */
741 10 Oct 06 olle 25 //  Xerver Free Web Server
741 10 Oct 06 olle 26 //  Copyright (C) 2002-2005 Omid Rouhani
741 10 Oct 06 olle 27 //
741 10 Oct 06 olle 28 //
741 10 Oct 06 olle 29 //  This program is free software; you can redistribute it and/or
741 10 Oct 06 olle 30 //  modify it under the terms of the GNU General Public License
741 10 Oct 06 olle 31 //  as published by the Free Software Foundation; either version 2
741 10 Oct 06 olle 32 //  of the License, or (at your option) any later version.
741 10 Oct 06 olle 33 //
741 10 Oct 06 olle 34 //  This program is distributed in the hope that it will be useful,
741 10 Oct 06 olle 35 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
741 10 Oct 06 olle 36 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
741 10 Oct 06 olle 37 //  GNU General Public License for more details.
741 10 Oct 06 olle 38 //
741 10 Oct 06 olle 39 //  You should have received a copy of the GNU General Public License
741 10 Oct 06 olle 40 //  along with this program; if not, write to the Free Software
741 10 Oct 06 olle 41 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
741 10 Oct 06 olle 42 //
741 10 Oct 06 olle 43 //
741 10 Oct 06 olle 44 //  #############################################################
741 10 Oct 06 olle 45 //  ##  YOU CAN CONTACT THE AUTHOR (OMID ROUHANI) AT:          ##
741 10 Oct 06 olle 46 //  ##  HTTP://WWW.JAVASCRIPT.NU/XERVER/                       ##
741 10 Oct 06 olle 47 //  ##                                                         ##
741 10 Oct 06 olle 48 //  ##  IF YOUR SOFTWARE IS NOT RELEASED UNDER THE             ##
741 10 Oct 06 olle 49 //  ##  GNU GENERAL PUBLIC LICENSE (GPL),                      ##
741 10 Oct 06 olle 50 //  ##  PLEASE DO NOT COPY ANYTHING FROM THIS SOURCE CODE!!!   ##
741 10 Oct 06 olle 51 //  ##                                                         ##
741 10 Oct 06 olle 52 //  ##  FOR FULL LICENSE, PLEASE READ "XERVER LICENSE".        ##
741 10 Oct 06 olle 53 //  #############################################################
1652 22 May 07 gregory 54 package se.lu.thep.coreftpd.common;
741 10 Oct 06 olle 55
741 10 Oct 06 olle 56 import java.io.DataInputStream;
741 10 Oct 06 olle 57 import java.io.InputStream;
741 10 Oct 06 olle 58
741 10 Oct 06 olle 59 /**
1652 22 May 07 gregory 60  * <B>About this class:</B> <BR>
1652 22 May 07 gregory 61  * The difference between <CODE>DataInputStreamWithReadLine</CODE> and <CODE>DataInputStream</CODE>
1652 22 May 07 gregory 62  * is that <CODE>DataInputStreamWithReadLine</CODE> has a method called "<CODE>String
1652 22 May 07 gregory 63  * myReadLine(int maxLineSize)</CODE>".
1652 22 May 07 gregory 64  * 
741 10 Oct 06 olle 65  * @author <a href="http://www.JavaScript.nu/xerver/" TARGET="_top">Omid Rouhani</a>
741 10 Oct 06 olle 66  * @version 1.0
741 10 Oct 06 olle 67  */
2418 22 Nov 07 gregory 68 final public class DataInputStreamWithReadLine
2418 22 Nov 07 gregory 69     extends DataInputStream
2418 22 Nov 07 gregory 70 {
1652 22 May 07 gregory 71   private final int i_bufferLength = 128; // Note: as myReadLine is recrusive,
2418 22 Nov 07 gregory 72   // you can make this value as
2418 22 Nov 07 gregory 73   // big/small as you want
2418 22 Nov 07 gregory 74   // (performance might however be
2418 22 Nov 07 gregory 75   // better/worse with other values).
2418 22 Nov 07 gregory 76   // The value of this DOES NOT set
2418 22 Nov 07 gregory 77   // the maximum length of the line
2418 22 Nov 07 gregory 78   // read!!! Arbitrary long lines can
2418 22 Nov 07 gregory 79   // be read anyway!
1652 22 May 07 gregory 80   private char c_lastLineBreakRead = ' '; // Enter anything but '\r' and '\n'
1652 22 May 07 gregory 81
2418 22 Nov 07 gregory 82
2418 22 Nov 07 gregory 83   // here and it will work fine!!
1652 22 May 07 gregory 84   public DataInputStreamWithReadLine(InputStream in) // now we can Extend
2418 22 Nov 07 gregory 85   // ReadInputStreamSTDIN
2418 22 Nov 07 gregory 86   // without problem
741 10 Oct 06 olle 87   {
741 10 Oct 06 olle 88     super(in);
741 10 Oct 06 olle 89   }
741 10 Oct 06 olle 90
2418 22 Nov 07 gregory 91
1652 22 May 07 gregory 92   /**
1652 22 May 07 gregory 93    * Reads a line of bytes from the stream. <BR>
1652 22 May 07 gregory 94    * The String returned does not contain \r or \n. <BR>
1652 22 May 07 gregory 95    * If a \r or \n is found as the very first byte in the stream it will be
1652 22 May 07 gregory 96    * removed from the stream. If there are additional \r or \n in the stream
1652 22 May 07 gregory 97    * these might, or might not, be removed!! <BR>
1652 22 May 07 gregory 98    * However, this method does guaranty that when you call it for the first
1652 22 May 07 gregory 99    * time, it will ignore the 3 first \r and \n in the very beginning of the
1652 22 May 07 gregory 100    * stream (if there are 3 (or less) \r or \n, that is) and then read one
1652 22 May 07 gregory 101    * line and then return it. For each and every time you call this method
1652 22 May 07 gregory 102    * later (without reading from the stream with another method) it will
1652 22 May 07 gregory 103    * successfully read one line and return it. <BR>
1652 22 May 07 gregory 104    * You have to guaranty that the lines are using one of these formats
1652 22 May 07 gregory 105    * (example with 6 lines, including one empty line): <BR>
1652 22 May 07 gregory 106    * "line1\nline2\nline3\n\nline5\nline6" <BR>
1652 22 May 07 gregory 107    * "line1\rline2\rline3\r\rline5\rline6" <BR>
1652 22 May 07 gregory 108    * "line1\r\nline2\r\nline3\r\n\r\nline5\r\nline6"
1652 22 May 07 gregory 109    * <P>
1652 22 May 07 gregory 110    * Other formats might, or might not, work with this method. <BR>
1652 22 May 07 gregory 111    * <BR>
1652 22 May 07 gregory 112    * This method does not use the reset() or mark() methods.
1652 22 May 07 gregory 113    * 
2418 22 Nov 07 gregory 114    * @param i_maxSizeToRead the maximum length of a line. If there is no \n or
2418 22 Nov 07 gregory 115    *        \r within the first i_maxSizeToRead bytes, the bytes read are
2418 22 Nov 07 gregory 116    *        converted into a String which is returned (with length
2418 22 Nov 07 gregory 117    *        i_maxSizeToRead)
1652 22 May 07 gregory 118    */
1652 22 May 07 gregory 119   // i_maxSizeToRead = the maximum length of a line. If there is no \n or \r
1652 22 May 07 gregory 120   // within the first i_maxSizeToRead bytes, the bytes read are converted into
1652 22 May 07 gregory 121   // a String which is returned (with length i_maxSizeToRead)
1652 22 May 07 gregory 122   public String myReadLine(int i_maxSizeToRead) // IMPORTANT: as the line is
2418 22 Nov 07 gregory 123   // buffered before it is
2418 22 Nov 07 gregory 124   // returned i_maxSizeToRead
2418 22 Nov 07 gregory 125   // is used so no one shall
2418 22 Nov 07 gregory 126   // be able to send a very
2418 22 Nov 07 gregory 127   // long line without any \r
2418 22 Nov 07 gregory 128   // or \n to eat all memory.
2418 22 Nov 07 gregory 129   // THIS IS A IMPORTANT
2418 22 Nov 07 gregory 130   // SECURITY ISSUE!!!
741 10 Oct 06 olle 131   {
741 10 Oct 06 olle 132     return myReadLineWithInitialNewLineCharacters(i_maxSizeToRead, true);
741 10 Oct 06 olle 133   }
741 10 Oct 06 olle 134
2418 22 Nov 07 gregory 135
741 10 Oct 06 olle 136   /**
1652 22 May 07 gregory 137    * <CODE>String myReadLine(int i_maxSizeToRead)</CODE> actually calls this
1652 22 May 07 gregory 138    * method with <CODE>myReadLineWithInitialNewLineCharacters(i_maxSizeToRead,
2418 22 Nov 07 gregory 139    * true)</CODE>. <BR>
1652 22 May 07 gregory 140    * <BR>
1652 22 May 07 gregory 141    * This method does not use the reset() or mark() methods.
1652 22 May 07 gregory 142    * 
2418 22 Nov 07 gregory 143    * @param i_maxSizeToRead the maximum length of a line. If there is no \n or
2418 22 Nov 07 gregory 144    *        \r within the first i_maxSizeToRead bytes, the bytes read are
2418 22 Nov 07 gregory 145    *        converted into a String which is returned (with length
2418 22 Nov 07 gregory 146    *        i_maxSizeToRead)
2418 22 Nov 07 gregory 147    * @param b_ignoreInitialNewLineCharacters If this is true then we will
2418 22 Nov 07 gregory 148    *        ignore the initial new line characters ("\n" and "\r")
1652 22 May 07 gregory 149    */
1652 22 May 07 gregory 150   private String myReadLineWithInitialNewLineCharacters(int i_maxSizeToRead,
1652 22 May 07 gregory 151       boolean b_ignoreInitialNewLineCharacters) // IMPORTANT: as the
2418 22 Nov 07 gregory 152   // line is buffered
2418 22 Nov 07 gregory 153   // before it is returned
2418 22 Nov 07 gregory 154   // i_maxSizeToRead is
2418 22 Nov 07 gregory 155   // used so no one shall
2418 22 Nov 07 gregory 156   // be able to send a
2418 22 Nov 07 gregory 157   // very long line
2418 22 Nov 07 gregory 158   // without any \r or \n
2418 22 Nov 07 gregory 159   // to eat all memory.
2418 22 Nov 07 gregory 160   // THIS IS A IMPORTANT
2418 22 Nov 07 gregory 161   // SECURITY ISSUE!!!
741 10 Oct 06 olle 162   {
1652 22 May 07 gregory 163     byte[] buffer = new byte[i_bufferLength];
741 10 Oct 06 olle 164     byte b;
741 10 Oct 06 olle 165     char c;
1652 22 May 07 gregory 166     int i = 0;
1652 22 May 07 gregory 167     int n = 0; // Number of buffered bytes
2418 22 Nov 07 gregory 168     try
2418 22 Nov 07 gregory 169     {
1652 22 May 07 gregory 170       int i_numberOfLineBreakRead = 0;
1652 22 May 07 gregory 171       boolean b_isFirstLoop = true;
2418 22 Nov 07 gregory 172       for (; i < i_bufferLength && i_maxSizeToRead > 0; i++)
2418 22 Nov 07 gregory 173       {
1652 22 May 07 gregory 174         b = readByte();
1652 22 May 07 gregory 175         c = (char) b;
2418 22 Nov 07 gregory 176         if (c == '\n' || c == '\r')
2418 22 Nov 07 gregory 177         {
1652 22 May 07 gregory 178           // If [we are not ignoring the first \r or \n] and [we are
1652 22 May 07 gregory 179           // at the first character of the stream]...
2418 22 Nov 07 gregory 180           if (!b_ignoreInitialNewLineCharacters && b_isFirstLoop)
2418 22 Nov 07 gregory 181           {
1652 22 May 07 gregory 182             // Then break here and return "".
1652 22 May 07 gregory 183             // This is necessary for this reason: if we have a
1652 22 May 07 gregory 184             // buffer length of 3 and a stream such as "abc\ndef"
1652 22 May 07 gregory 185             // then we don't want the readLine to return the string
1652 22 May 07 gregory 186             // "abcdef", but only "abc". To avoid this bug we have
1652 22 May 07 gregory 187             // this check.
1652 22 May 07 gregory 188             return "";
1652 22 May 07 gregory 189           }
1652 22 May 07 gregory 190           i_numberOfLineBreakRead++;
1652 22 May 07 gregory 191           // IF [this is NOT the very first line read (reason: DO NOT
1652 22 May 07 gregory 192           // return "" BEFORE line2:
1652 22 May 07 gregory 193           // "line1\r\nline2\r\n\r\nline3\r\n")]
1652 22 May 07 gregory 194           // OR [we have read 3 line breaks (in normal case: this will
1652 22 May 07 gregory 195           // be "\n\r\n") (reason: return "" after line2:
1652 22 May 07 gregory 196           // "line1\r\nline2\r\n\r\nline3\r\n")]
1652 22 May 07 gregory 197           // OR [the first charcter we find now is the same as the
1652 22 May 07 gregory 198           // last line break character read last time this method was
1652 22 May 07 gregory 199           // called (reason: return "" after line2:
1652 22 May 07 gregory 200           // "line1\nline2\n\nline3\n")]
2418 22 Nov 07 gregory 201           if (!b_isFirstLoop || i_numberOfLineBreakRead == 3 || (c_lastLineBreakRead == c && i_numberOfLineBreakRead == 1)) // If
2418 22 Nov 07 gregory 202           // [the
2418 22 Nov 07 gregory 203           // first
2418 22 Nov 07 gregory 204           // byte
2418 22 Nov 07 gregory 205           // was
2418 22 Nov 07 gregory 206           // a \r
2418 22 Nov 07 gregory 207           // or
2418 22 Nov 07 gregory 208           // \n]
2418 22 Nov 07 gregory 209           // OR
2418 22 Nov 07 gregory 210           // [we
2418 22 Nov 07 gregory 211           // have
2418 22 Nov 07 gregory 212           // read
2418 22 Nov 07 gregory 213           // the
2418 22 Nov 07 gregory 214           // \r
2418 22 Nov 07 gregory 215           // or
2418 22 Nov 07 gregory 216           // \n
2418 22 Nov 07 gregory 217           // after
2418 22 Nov 07 gregory 218           // our
2418 22 Nov 07 gregory 219           // line
2418 22 Nov 07 gregory 220           // (or,
2418 22 Nov 07 gregory 221           // it's
2418 22 Nov 07 gregory 222           // a
2418 22 Nov 07 gregory 223           // real
2418 22 Nov 07 gregory 224           // empty
2418 22 Nov 07 gregory 225           // line,
2418 22 Nov 07 gregory 226           // such
2418 22 Nov 07 gregory 227           // as
2418 22 Nov 07 gregory 228           // "\n\n"
2418 22 Nov 07 gregory 229           // in
2418 22 Nov 07 gregory 230           // this
2418 22 Nov 07 gregory 231           // example:
2418 22 Nov 07 gregory 232           // "line1\nline2\n\nline3\nline4\n".
2418 22 Nov 07 gregory 233           // Note
2418 22 Nov 07 gregory 234           // that
2418 22 Nov 07 gregory 235           // the
2418 22 Nov 07 gregory 236           // example
2418 22 Nov 07 gregory 237           // line
2418 22 Nov 07 gregory 238           // given,
2418 22 Nov 07 gregory 239           // or
2418 22 Nov 07 gregory 240           // the
2418 22 Nov 07 gregory 241           // one
2418 22 Nov 07 gregory 242           // below,
2418 22 Nov 07 gregory 243           // both
2418 22 Nov 07 gregory 244           // will
2418 22 Nov 07 gregory 245           // work
2418 22 Nov 07 gregory 246           // well
2418 22 Nov 07 gregory 247           // with
2418 22 Nov 07 gregory 248           // this
2418 22 Nov 07 gregory 249           // "read-line-algorithm":
2418 22 Nov 07 gregory 250           // "line1\r\nline2\r\nline3\r\n\r\nline4\r\nLine5")]
1652 22 May 07 gregory 251           {
1652 22 May 07 gregory 252             c_lastLineBreakRead = c;
1652 22 May 07 gregory 253             if (n > 0)
1652 22 May 07 gregory 254               return new String(buffer, 0, n);
2418 22 Nov 07 gregory 255             return "";
1652 22 May 07 gregory 256           }
2418 22 Nov 07 gregory 257         }
2418 22 Nov 07 gregory 258         else
2418 22 Nov 07 gregory 259         {
1652 22 May 07 gregory 260           i_maxSizeToRead--;
1652 22 May 07 gregory 261           buffer[n++] = b;
1652 22 May 07 gregory 262           b_isFirstLoop = false;
741 10 Oct 06 olle 263         }
741 10 Oct 06 olle 264       }
741 10 Oct 06 olle 265     }
2418 22 Nov 07 gregory 266     catch (Exception e)
2418 22 Nov 07 gregory 267     {}
1652 22 May 07 gregory 268     c_lastLineBreakRead = ' '; // We have gone out of the loop the "normal
2418 22 Nov 07 gregory 269     // way" (we did not run "return xxx" in the
2418 22 Nov 07 gregory 270     // loop.)
1652 22 May 07 gregory 271     // IMPORTANT: If we get an Exception above, it's possible to come here
1652 22 May 07 gregory 272     // with the values n=0 and i_maxSizeToRead="the value given as the
1652 22 May 07 gregory 273     // argument". If we then recursively call this function again with the
1652 22 May 07 gregory 274     // same value to i_maxSizeToRead and the error is a kind of error that
1652 22 May 07 gregory 275     // does always come (for me it was EOFException) we will loop
1652 22 May 07 gregory 276     // recursively forever without changing the value of n and
1652 22 May 07 gregory 277     // i_maxSizeToRead!!! AVOID THIS! We avoid this by returing "" if n=0
1652 22 May 07 gregory 278     // (which will make this function to work good and as Expected).
1652 22 May 07 gregory 279     if (n == 0)
741 10 Oct 06 olle 280       return "";
1652 22 May 07 gregory 281     else if (i == i_bufferLength) // If [\r or \n has not been found
2418 22 Nov 07 gregory 282       // within the first "i_bufferLength"
2418 22 Nov 07 gregory 283       // bytes]...
2418 22 Nov 07 gregory 284       return new String(buffer, 0, n) + myReadLineWithInitialNewLineCharacters(
2418 22 Nov 07 gregory 285         i_maxSizeToRead, false); // We have false so that we shall
2418 22 Nov 07 gregory 286                       // not ignore
2418 22 Nov 07 gregory 287     // the initial \r or \n in the remaining of
2418 22 Nov 07 gregory 288     // the input stream. (if our for example is
2418 22 Nov 07 gregory 289     // 3 characters long and the stream contains
2418 22 Nov 07 gregory 290     // "abc\ndef", then this prevents the \n to
2418 22 Nov 07 gregory 291     // be ignored (and hence the entire string
2418 22 Nov 07 gregory 292     // abcdef is read as one single line))
741 10 Oct 06 olle 293     else
1652 22 May 07 gregory 294       return new String(buffer, 0, n);
741 10 Oct 06 olle 295   }
741 10 Oct 06 olle 296 }