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}