001package com.hfg.util.io;
002
003import java.io.FilterReader;
004import java.io.IOException;
005import java.io.Reader;
006
007import com.hfg.math.Range;
008
009//------------------------------------------------------------------------------
010/**
011 FilterReader that provides the specified segment of the stream.
012 <div>
013 @author J. Alex Taylor, hairyfatguy.com
014 </div>
015 */
016//------------------------------------------------------------------------------
017// com.hfg Library
018//
019// This library is free software; you can redistribute it and/or
020// modify it under the terms of the GNU Lesser General Public
021// License as published by the Free Software Foundation; either
022// version 2.1 of the License, or (at your option) any later version.
023//
024// This library is distributed in the hope that it will be useful,
025// but WITHOUT ANY WARRANTY; without even the implied warranty of
026// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
027// Lesser General Public License for more details.
028//
029// You should have received a copy of the GNU Lesser General Public
030// License along with this library; if not, write to the Free Software
031// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
032//
033// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
034// jataylor@hairyfatguy.com
035//------------------------------------------------------------------------------
036
037public class SegmentReader extends FilterReader
038{
039   private Range<Integer> mSegment;
040   private char[]  mBuffer;
041   private int     mBufferLimit;
042   private int     mBufferIndex;
043   private boolean mEndOfStreamReached;
044   private int     mNumBytes;
045
046   //###########################################################################
047   // CONSTRUCTORS
048   //###########################################################################
049
050   //---------------------------------------------------------------------------
051   public SegmentReader(Reader inReader, Range<Integer> inSegment)
052   {
053      super(inReader);
054      mSegment = inSegment;
055      if (mSegment != null
056          && null == mSegment.getStart())
057      {
058         mSegment.setStart(1);
059      }
060   }
061
062   //###########################################################################
063   // PUBLIC METHODS
064   //###########################################################################
065
066   //---------------------------------------------------------------------------
067   @Override
068   public int read(char[] inBuffer, int inOffset, int inMaxReadLength)
069         throws IOException
070   {
071      int theChar;
072      int numCharsRead = 0;
073      do
074      {
075         theChar = read();
076         if (theChar > 0)
077         {
078            inBuffer[inOffset++] = (char) theChar;
079            numCharsRead++;
080         }
081      }
082      while (theChar >= 0
083            && numCharsRead < inMaxReadLength);
084
085      return (theChar < 0 && 0 == numCharsRead ? -1 : numCharsRead);
086   }
087
088   //---------------------------------------------------------------------------
089   @Override
090   public int read()
091         throws IOException
092   {
093      if (null == mBuffer)
094      {
095         // Initialize
096         mBuffer = new char[8196];
097
098         if (mSegment != null
099             && mSegment.getStart() > 1)
100         {
101            super.in.skip(mSegment.getStart() - 1);
102         }
103      }
104
105      if (mBufferIndex >= mBufferLimit)
106      {
107         fillBuffer();
108      }
109
110      return (mEndOfStreamReached ? -1 : mBuffer[mBufferIndex++]);
111   }
112
113   //###########################################################################
114   // PRIVATE METHODS
115   //###########################################################################
116
117   //---------------------------------------------------------------------------
118   private void fillBuffer()
119         throws IOException
120   {
121      int fillSize = mBuffer.length;
122      if (mSegment !=  null
123          && mSegment.getEnd() != null)
124      {
125         int remainingBytesToRead = mSegment.length().intValue() - mNumBytes;
126         fillSize = Math.min(fillSize, remainingBytesToRead);
127      }
128
129      if (fillSize > 0)
130      {
131         mBufferLimit = super.in.read(mBuffer, 0, fillSize);
132         if (mBufferLimit > 0)
133         {
134            mNumBytes += mBufferLimit;
135         }
136      }
137      else
138      {
139         mBufferLimit = -1;
140      }
141
142      if (-1 == mBufferLimit)
143      {
144         mEndOfStreamReached = true;
145      }
146
147      // Reset the index
148      mBufferIndex = 0;
149   }
150}