DotKludgeStream.java

/*
** Module   : DotKludgeStream.java
** Abstract : Implements an input stream which is guaranteed to contain
**            the single dot character at the end.
**
** Copyright (c) 2004-2017, Golden Code Development Corporation.
**
** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
** 001 NVS 20041224 NEW   @19099 Created. Needed a class that would guarantee
**                               than an input stream terminates with the dot.
** 002 GES 20070425 CHG   @33292 If the contained stream supports mark/reset 
**                               then the state is properly maintained.
*/
/*
** 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 may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.uast;

import java.io.*;

/**
 * Implements a simple input stream based on an underlying input stream, which
 * logically appends the dot character to the underlying input stream in case
 * the latter terminates with anything else.
 * <p>
 * This class is used in the {@link ProgressLexer} to handle files where the
 * last statement is not followed by the dot.
 * <p>
 * @author NVS
 */
public class DotKludgeStream
extends FilterInputStream
{
   /** Keeps the last read character. */
   private int lastChar = -1;
   
   /** Next read will signal EOF condition on the underlying stream. */
   private boolean eof = false;
   
   /** Keeps the last read character at the mark point. */
   private int markChar = -1;
   
   /** Next read after mark point will signal EOF condition. */
   private boolean markEof = false;
   
   /**
    * Constructor.
    *
    * @param   in
    *          an input stream of any kind.
    */
   public DotKludgeStream(InputStream in)
   {
      super(in);
   }

   /**
    * Marks the current position in this input stream. A subsequent call to
    * the reset method repositions this stream at the last marked position
    * so that subsequent reads re-read the same bytes.
    * <p>
    * The general contract of mark is that, if the method markSupported
    * returns <code>true</code>, the stream remembers all the bytes read
    * after the call to mark and stands ready to supply those same bytes
    * again if and whenever the method reset is called. However, the stream
    * is not required to remember any data at all if more than readlimit
    * bytes are read from the stream before reset is called.
    * <p>
    * Maintains state necessary to restore the current read position.
    *
    * @param    readlimit
    *           The maximum limit of bytes that can be read before the mark
    *           position becomes invalid.
    */
   public void mark(int readlimit)
   {
      super.mark(readlimit);
      
      // save state
      markChar = lastChar;
      markEof  = eof;
   }
   
   /**
    * Repositions this stream to the position at the time the mark method
    * was last called on this input stream.
    *
    * throws   IOException
    *          If the stream has not been marked, or if the mark has been
    *          invalidated, or if the stream does not support reset(), or if
    *          some other I/O error occurs.
    */
   public void reset()
   throws IOException
   {
      super.reset();
      
      // restore state if no exception occurred
      lastChar = markChar;
      eof      = markEof;
   }

   /**
    * Reads the next byte from the input stream. At EOF, checks if the last
    * read character was the dot, and inserts one before returning EOF,
    * if not. All white space characters are excluded from consideration.
    *
    * @return    byte read from the underlying stream or the dot character
    *            or -1 at EOF.
    * @throws    IOException
    */
   public int read()
   throws IOException
   {
      if (eof)
         return -1;
      
      int nextChar = super.read();
      if (nextChar != -1)
      {
         if (nextChar != '\r' && nextChar != '\n' && 
             nextChar != '\t' && nextChar != ' ') 
         lastChar = nextChar;
         return nextChar;
      }
      else
      {
         eof = true;
         if (lastChar == '.')
            return -1;
         else
            return '.';   
      }
   }
}