001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.functions.file;
020
021import java.io.BufferedReader;
022import java.io.File;
023import java.io.IOException;
024import java.io.RandomAccessFile;
025
026import lucee.commons.io.IOUtil;
027import lucee.commons.io.res.Resource;
028import lucee.runtime.exp.PageException;
029import lucee.runtime.exp.PageRuntimeException;
030import lucee.runtime.op.Caster;
031
032public class FileStreamWrapperRead extends FileStreamWrapper {
033        
034
035        private BufferedReader br;
036        private String charset;
037        private boolean seekable;
038        private RandomAccessFile raf;
039
040        /**
041         * Constructor of the class
042         * @param res
043         * @param charset
044         * @throws IOException
045         */
046        public FileStreamWrapperRead(Resource res, String charset,boolean seekable) {
047                super(res);
048                this.charset=charset;
049                this.seekable=seekable;
050        }
051        
052        @Override
053        public Object read(int len) throws IOException {
054                if(seekable) {
055                        byte[] barr=new byte[len];
056            len = getRAF().read(barr);
057            if(len==-1) throw new IOException("End of file reached");
058            return new String(barr, 0, len, charset);
059                }
060                
061                char[] carr=new char[len];
062                len = _getBR().read(carr);
063                if(len==-1) throw new IOException("End of file reached");
064                
065                return new String(carr,0,len);
066        }
067
068        @Override
069        public String readLine() throws IOException {
070                if(seekable) {
071                        return getRAF().readLine();
072                }
073                
074                if(!_getBR().ready())
075                        throw new IOException(" End of file reached");
076                return _getBR().readLine();
077        }
078
079        @Override
080        public void close() throws IOException {
081                super.setStatus(FileStreamWrapper.STATE_CLOSE);
082                if(br!=null)br.close();
083                if(raf!=null)raf.close();
084        }
085
086        @Override
087        public String getMode() {
088                return "read";
089        }
090
091        public boolean isEndOfFile() {
092                if(seekable){
093                        long pos=0;
094                        try {
095                                pos = getRAF().getFilePointer();
096                        } catch (IOException ioe) {
097                                throw new PageRuntimeException(Caster.toPageException(ioe));
098                        }
099                        try {
100                                if(raf.read()==-1) return true;
101                                raf.seek(pos);
102                        } 
103                        catch (IOException e) {
104                                return true;
105                        }
106                        return false;
107                }
108                
109                try {
110                        return !_getBR().ready();
111                } catch (IOException e) {
112                        return true;
113                }
114        }
115
116        @Override
117        public long getSize() {
118                return res.length();
119        }
120
121        @Override
122        public void skip(int len) throws PageException {
123                if(seekable){
124                        try {
125                                getRAF().skipBytes(len);
126                        } catch (IOException e) {
127                                throw Caster.toPageException(e);
128                        }
129                        return;
130                }
131                
132                try {
133                        _getBR().skip(len);
134                        return;
135                } 
136                catch (IOException e) {}
137                        
138                throw Caster.toPageException(new IOException("skip is only supported when you have set argument seekable of function fileOpen to true"));
139        }
140        public void seek(long pos) throws PageException {
141                if(seekable){
142                        try {
143                                getRAF().seek(pos);
144                        } catch (IOException e) {
145                                throw Caster.toPageException(e);
146                        }
147                }
148                else throw Caster.toPageException(new IOException("seek is only supported when you have set argument seekable of function fileOpen to true"));
149        }
150
151        private RandomAccessFile getRAF() throws IOException {
152                if(raf==null){
153                        if(!(res instanceof File))
154                                throw new IOException("only resources for local filesytem support seekable");
155                        
156                        raf = new RandomAccessFile((File)res,"r");
157                }
158                return raf;
159        }
160
161
162        private BufferedReader _getBR() throws IOException {
163                if(br==null){
164                        br = IOUtil.toBufferedReader(IOUtil.getReader(res.getInputStream(),charset));
165                }
166                return br;
167        }
168}