001package com.hfg.util.io;
002
003import java.io.FilterInputStream;
004import java.io.InputStream;
005import java.io.IOException;
006
007
008//------------------------------------------------------------------------------
009/**
010 An InputStream variant for reading up to a specified marker.
011 <div>
012   @author J. Alex Taylor, hairyfatguy.com
013 </div>
014 */
015//------------------------------------------------------------------------------
016// com.hfg XML/HTML Coding Library
017//
018// This library is free software; you can redistribute it and/or
019// modify it under the terms of the GNU Lesser General Public
020// License as published by the Free Software Foundation; either
021// version 2.1 of the License, or (at your option) any later version.
022//
023// This library is distributed in the hope that it will be useful,
024// but WITHOUT ANY WARRANTY; without even the implied warranty of
025// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
026// Lesser General Public License for more details.
027//
028// You should have received a copy of the GNU Lesser General Public
029// License along with this library; if not, write to the Free Software
030// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
031//
032// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
033// jataylor@hairyfatguy.com
034//------------------------------------------------------------------------------
035
036public class InputStreamSegment extends FilterInputStream
037{
038   //##########################################################################
039   // PRIVATE FIELDS
040   //##########################################################################
041
042   private byte[]  mSegmentEndMarker;
043   private byte[]  mBuffer;
044   private int     mBufferPtr;
045   private int     mBufferLimit;
046   private int     mBufferReadLimit;
047   private boolean mEndOfSegmentReached = false;
048
049
050   private static int sDefaultBufferSize = 4 * 1024;
051
052   //##########################################################################
053   // CONSTRUCTORS
054   //##########################################################################
055
056   //--------------------------------------------------------------------------
057   public InputStreamSegment(InputStream inStream, byte[] inSegmentEndMarker)
058   {
059      super(inStream);
060
061      if (0 == inSegmentEndMarker.length)
062      {
063         throw new RuntimeException("No segment end marker was specifed!");
064      }
065
066      mSegmentEndMarker = inSegmentEndMarker;
067      mBuffer = new byte[(inSegmentEndMarker.length * 2 > sDefaultBufferSize ? inSegmentEndMarker.length * 2 : sDefaultBufferSize)];
068   }
069
070   //##########################################################################
071   // PUBLIC METHODS
072   //##########################################################################
073
074   //--------------------------------------------------------------------------
075   public InputStreamSegment setBufferSize(int inValue)
076   {
077      if (inValue < mSegmentEndMarker.length)
078      {
079         throw new RuntimeException("The buffer size cannot be smaller than the size of the segment end marker!");
080      }
081
082      mBuffer = new byte[inValue];
083
084      return this;
085   }
086
087   //--------------------------------------------------------------------------
088   public int read()
089         throws IOException
090   {
091      if (mBufferPtr >= mBufferReadLimit)
092      {
093         if (!mEndOfSegmentReached)
094         {
095           fillBuffer();
096         }
097         else
098         {
099            return -1;
100         }
101      }
102
103      return (mBufferPtr < mBufferReadLimit ? (int) mBuffer[mBufferPtr++] & 0xff : -1);
104   }
105
106   //--------------------------------------------------------------------------
107   public int read(byte[] buffer, int offset, int length)
108         throws IOException
109   {
110      int index = offset;
111      int theChar = 0;
112      while (index - offset < length
113             && (theChar = read()) != -1)
114      {
115         buffer[index++] = (byte) theChar;
116      }
117
118      int bytesRead = index - offset;
119      if (0 == bytesRead
120          && -1 == theChar)
121      {
122         bytesRead = -1;
123      }
124
125      return bytesRead;
126   }
127
128
129   //##########################################################################
130   // PRIVATE METHODS
131   //##########################################################################
132
133   //--------------------------------------------------------------------------
134   private void fillBuffer()
135         throws IOException
136   {
137      int markerIndex = mBufferLimit - mBufferReadLimit;
138
139      // Move leftover content to the beginning of the buffer
140      if (mBufferPtr > 0)
141      {
142         System.arraycopy(mBuffer, mBufferReadLimit, mBuffer, 0, mBufferLimit - mBufferReadLimit);
143         mBufferPtr = 0;
144         mBufferLimit = mBufferLimit - mBufferReadLimit;
145         mBufferReadLimit = 0;
146      }
147
148      while (mBufferLimit < mBuffer.length)
149      {
150         int nextChar = in.read();
151         if (-1 == nextChar)
152         {
153            throw new IOException("End of stream reached without detecting the segment end marker '" + new String(mSegmentEndMarker) + "'!");
154         }
155
156         mBuffer[mBufferLimit++] = (byte) nextChar;
157         if (nextChar == mSegmentEndMarker[markerIndex])
158         {
159            if (markerIndex == mSegmentEndMarker.length - 1)
160            {
161               // Found the segment end marker.
162               mEndOfSegmentReached = true;
163               break;
164            }
165
166            markerIndex++;
167         }
168         else
169         {
170            if (nextChar == mSegmentEndMarker[0])
171            {
172               mBufferReadLimit += markerIndex;
173               markerIndex = 1;
174            }
175            else
176            {
177               mBufferReadLimit += (markerIndex + 1);
178               markerIndex = 0;
179            }
180         }
181      }
182   }
183}