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    }