001 /*
002 * LAPIS lightweight structured text processing system
003 *
004 * Copyright (C) 1998-2002 Carnegie Mellon University,
005 * Copyright (C) 2003 Massachusetts Institute of Technology.
006 * All rights reserved.
007 *
008 * This library is free software; you can redistribute it
009 * and/or modify it under the terms of the GNU General
010 * Public License as published by the Free Software
011 * Foundation, version 2.
012 *
013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014 */
015
016 package lapisx.net;
017
018 import java.io.*;
019
020 public class ContentTypeGuessingReader extends Reader {
021 public static lapisx.util.Debug debug = lapisx.util.Debug.QUIET;
022 String contentType;
023 char[] head = new char[200];
024 int start, end;
025 Reader tail;
026
027 public ContentTypeGuessingReader (Reader in) throws IOException {
028 start = 0;
029 end = in.read (head);
030 tail = in;
031 if (end == -1)
032 return;
033
034 String strHeader = new String (head, start, end);
035 strHeader = strHeader.trim ();
036 strHeader = strHeader.toLowerCase ();
037 debug.println ("CTGR read '" + strHeader + "'");
038
039 if (strHeader.startsWith ("<html>")
040 || strHeader.startsWith ("<!doctype html")
041 || strHeader.startsWith ("<title>") // for directories
042 ) {
043 contentType = "text/html";
044 } else if (strHeader.startsWith ("content-type:")) {
045 // Scan for newline (marking end of Content-type field);
046 // then scan for double newline (marking end of header) so we can
047 // omit the header from the document
048 StringBuffer typebuf = new StringBuffer ();
049 boolean readingContentType = true;
050 boolean sawNewline = false;
051 for (int i = "content-type:".length (); true; ++i) {
052 if (i >= end) {
053 end = in.read (head);
054 if (end <= 0) {
055 end = 0;
056 break;
057 }
058 i = 0;
059 }
060 char c = head[i];
061 if (c == '\n') {
062 readingContentType = false;
063 if (sawNewline) {
064 start = i+1;
065 break;
066 }
067 else
068 sawNewline = true;
069 } else if (c != '\r') {
070 sawNewline = false;
071 if (readingContentType)
072 typebuf.append (c);
073 }
074 }
075
076 contentType = typebuf.toString ();
077 contentType = contentType.trim ();
078 }
079 debug.println ("CTGR guessed content-type " + contentType);
080 }
081
082 public String getContentType () {
083 return contentType;
084 }
085
086 public int read () throws IOException {
087 if (start < end)
088 return head[++start];
089 else
090 return tail.read ();
091 }
092
093 public int read (char[] b) throws IOException {
094 return read (b, 0, b.length);
095 }
096
097 public int read (char[] b, int off, int len) throws IOException {
098 if (start < end) {
099 int n = Math.min (end-start, len);
100 System.arraycopy (head, start, b, off, n);
101 start += n;
102
103 if (n < len) {
104 int n2 = tail.read (b, off+n, len-n);
105 if (n2 >= 0)
106 n += n2;
107 }
108 return n;
109 }
110 else
111 return tail.read (b, off, len);
112 }
113
114 public long skip (long n) throws IOException {
115 if (start < end) {
116 long n2 = Math.min ((long) (end-start), n);
117 start += (int)n2;
118
119 if (n2 < n)
120 n2 += tail.skip (n - n2);
121 return n2;
122 }
123 else
124 return tail.skip (n);
125 }
126
127 public boolean ready () throws IOException {
128 return (end > start) || tail.ready ();
129 }
130
131 public void close () throws IOException {
132 tail.close ();
133 }
134
135 public void mark (int readlimit) {
136 }
137
138 public void reset () throws IOException {
139 throw new IOException ("reset not supported");
140 }
141
142 public boolean markSupported () {
143 return false;
144 }
145 }