--- /dev/null
+// SSIStream.java\r
+// $Id: SSIStream.java,v 1.1 2010/06/15 12:26:36 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.ssi ;\r
+\r
+import java.io.FilterInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+import java.io.RandomAccessFile;\r
+\r
+import org.w3c.jigsaw.http.ClientException;\r
+import org.w3c.jigsaw.http.Reply;\r
+\r
+import org.w3c.jigsaw.ssi.commands.ControlCommandException;\r
+\r
+/**\r
+ * This stream concatenates the output streams of each of the segments.\r
+ * (It absorbs IOExceptions, so that a failure of a segment doesn't\r
+ * stop the emission).\r
+ * @author Antonio Ramirez <anto@mit.edu>\r
+ * @author Benoit Mahe <bmahe@sophia.inria.fr>\r
+ */\r
+\r
+class SSIStream extends FilterInputStream {\r
+\r
+ private Segment[] segments ;\r
+ private Reply[] replies ;\r
+ private RandomAccessFile file ;\r
+\r
+ private int curSeg = 0 ;\r
+ protected boolean cacheValid = true;\r
+\r
+ private boolean nextSegment()\r
+ {\r
+ try {\r
+ if(in != null) in.close() ;\r
+ } catch(IOException ex) {\r
+ // nil\r
+ }\r
+ while(curSeg < segments.length) { //-1\r
+ Segment seg = segments[curSeg] ;\r
+ if(seg.isControl()) { \r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ feeding control segment "+\r
+ curSeg+": "+\r
+ segments[curSeg]) ;\r
+ try {\r
+ curSeg = segments[curSeg].jumpTo(); \r
+ } catch (ControlCommandException ex) {\r
+ System.out.println(ex.getMessage());\r
+ ex.printStackTrace();\r
+ return false;\r
+ }\r
+ } else if(!seg.isUnparsed()) { \r
+ if (! cacheValid) {\r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ revalidate cache segment "+\r
+ curSeg+": "+\r
+ segments[curSeg]) ;\r
+ replies[curSeg] = segments[curSeg].get();\r
+ } else if (segments[curSeg].needsRevalidate()) {\r
+ replies[curSeg] = segments[curSeg].get();\r
+ }\r
+ if(replies[curSeg] != null) {\r
+ in = replies[curSeg].openStream() ;\r
+ if(in != null) {\r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ feeding command segment "+\r
+ curSeg+": "+\r
+ segments[curSeg]) ;\r
+ curSeg++;\r
+ return true ;\r
+ } else if (SSIFrame.debug) {\r
+ System.out.println("@@@@ not feeding command segment "+\r
+ curSeg+": "+\r
+ segments[curSeg]) ;\r
+ }\r
+ }\r
+ curSeg++; \r
+ } else {\r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ feeding Unparsed segment "+\r
+ curSeg+": "+\r
+ segments[curSeg]) ;\r
+ try {\r
+ in = new SegmentInputStream(file,\r
+ seg.start,\r
+ seg.end - seg.start) ;\r
+ curSeg++;\r
+ return true ;\r
+ } catch(IOException ex) {\r
+ // nil\r
+ }\r
+ }\r
+ }\r
+\r
+ in = null ;\r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ no more segments") ;\r
+ return false ;\r
+ }\r
+\r
+ public SSIStream(boolean cacheValid,\r
+ Segment[] segments,\r
+ Reply[] replies,\r
+ RandomAccessFile file)\r
+ throws IOException, ClientException\r
+ {\r
+ super((InputStream) null) ;\r
+\r
+ this.segments = segments ;\r
+ this.replies = replies ;\r
+ this.file = file ;\r
+ this.cacheValid = cacheValid ;\r
+\r
+ nextSegment() ;\r
+ }\r
+\r
+ public int read()\r
+ throws IOException\r
+ {\r
+ int data = -1 ;\r
+ try {\r
+ data = in.read() ;\r
+ } catch(IOException ex) {\r
+ if(SSIFrame.debug) \r
+ System.out.println("@@@@ absorbed exception: "+\r
+ ex.getMessage()) ;\r
+ data = -1 ;\r
+ } finally {\r
+ if(data != -1) return data ;\r
+ else {\r
+ if(!nextSegment()) return -1 ;\r
+ else return read() ;\r
+ }\r
+ } \r
+ }\r
+\r
+ public int read(byte b[],int off, int len)\r
+ throws IOException\r
+ {\r
+ int result = -1 ;\r
+ try {\r
+ result = in.read(b,off,len) ;\r
+ } catch(IOException ex) {\r
+ if(SSIFrame.debug)\r
+ System.out.println("@@@@ absorbed exception: "+\r
+ ex.getMessage()) ;\r
+ result = -1 ;\r
+ } finally {\r
+ if(result != -1) return result ;\r
+ else {\r
+ if(!nextSegment()) return -1 ;\r
+ else return read(b,off,len) ;\r
+ }\r
+ }\r
+ }\r
+\r
+ public long skip(long n)\r
+ throws IOException\r
+ {\r
+ return in.skip(n) ;\r
+ }\r
+\r
+ public int available()\r
+ throws IOException\r
+ {\r
+ return in.available() ;\r
+ }\r
+\r
+ public void close()\r
+ throws IOException\r
+ {\r
+ if(in != null) in.close() ;\r
+ file.close();\r
+ }\r
+\r
+ public synchronized void mark()\r
+ {\r
+ // nil\r
+ }\r
+\r
+ public synchronized void reset()\r
+ throws IOException\r
+ {\r
+ throw new IOException("mark not supported") ;\r
+ }\r
+\r
+ public boolean markSupported()\r
+ {\r
+ return false ;\r
+ }\r
+}\r
+\r
+/**\r
+ * Provides an unparsed segment in the input file as an InputStream\r
+ */\r
+class SegmentInputStream extends InputStream {\r
+\r
+ private RandomAccessFile file ;\r
+\r
+ private long bytesLeft ;\r
+\r
+ SegmentInputStream(RandomAccessFile file, long start, long length)\r
+ throws IOException\r
+ {\r
+ this.file = file ;\r
+ file.seek(start) ;\r
+ bytesLeft = length ;\r
+ }\r
+\r
+ public final void close()\r
+ throws IOException\r
+ {\r
+ // nil\r
+ }\r
+\r
+ public final int read()\r
+ throws IOException\r
+ {\r
+ if(bytesLeft>0) {\r
+ bytesLeft--;\r
+ return file.read() ;\r
+ } else return -1 ;\r
+ }\r
+\r
+ public final int read(byte b[], int off, int len)\r
+ throws IOException\r
+ {\r
+ if(bytesLeft==0) return -1 ;\r
+ if(len > bytesLeft)\r
+ len = (int) bytesLeft ;\r
+ file.readFully(b,off,len) ;\r
+ bytesLeft -= len ;\r
+ return len ;\r
+ }\r
+\r
+ public final int read(byte b[])\r
+ throws IOException\r
+ {\r
+ return this.read(b,0,b.length) ;\r
+ }\r
+\r
+ public final void reset()\r
+ throws IOException\r
+ {\r
+ throw new IOException("mark not supported") ;\r
+ }\r
+\r
+ public final void mark(int readlimit)\r
+ {\r
+ // nil\r
+ }\r
+\r
+ public final boolean markSupported()\r
+ {\r
+ return false ;\r
+ }\r
+\r
+ public final long skip(long n)\r
+ throws IOException\r
+ {\r
+ if(n>bytesLeft) n = bytesLeft ;\r
+ return file.skipBytes((int)n) ; // hmm...\r
+ }\r
+\r
+ public final int available() {\r
+ return (int) bytesLeft;\r
+ }\r
+\r
+}\r
+\r
+\r