001/**
002 * Copyright (c) 2014, the Railo Company Ltd.
003 * Copyright (c) 2016, Lucee Assosication Switzerland
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.commons.io;
020
021import java.io.BufferedInputStream;
022import java.io.BufferedOutputStream;
023import java.io.BufferedReader;
024import java.io.BufferedWriter;
025import java.io.ByteArrayInputStream;
026import java.io.ByteArrayOutputStream;
027import java.io.Closeable;
028import java.io.File;
029import java.io.FileInputStream;
030import java.io.FileNotFoundException;
031import java.io.FileOutputStream;
032import java.io.IOException;
033import java.io.InputStream;
034import java.io.InputStreamReader;
035import java.io.OutputStream;
036import java.io.OutputStreamWriter;
037import java.io.PrintStream;
038import java.io.Reader;
039import java.io.StringWriter;
040import java.io.UnsupportedEncodingException;
041import java.io.Writer;
042import java.lang.reflect.Method;
043import java.nio.charset.Charset;
044import java.sql.Connection;
045import java.sql.ResultSet;
046import java.util.LinkedList;
047import java.util.zip.ZipFile;
048
049import javax.mail.Transport;
050
051import org.apache.http.client.methods.HttpRequestBase;
052import org.apache.http.impl.client.CloseableHttpClient;
053import org.apache.http.protocol.HttpContext;
054
055import lucee.print;
056import lucee.commons.io.res.Resource;
057import lucee.commons.lang.ExceptionUtil;
058import lucee.commons.lang.StringUtil;
059import lucee.commons.net.URLEncoder;
060import lucee.commons.net.http.httpclient4.HTTPResponse4Impl;
061import lucee.runtime.PageContext;
062import lucee.runtime.engine.ThreadLocalPageContext;
063import lucee.runtime.exp.PageException;
064import lucee.runtime.op.Caster;
065import lucee.runtime.tag.Http41;
066import net.sf.jmimemagic.Magic;
067import net.sf.jmimemagic.MagicMatch;
068
069import com.lowagie.text.Document;
070
071/**
072 * I/O Util 
073 */
074public final class IOUtil {
075
076    /**
077     * copy a inputstream to a outputstream
078     * @param in 
079     * @param out
080     * @param closeIS 
081     * @param closeOS 
082     * @throws IOException
083     */
084    public static final void copy(InputStream in, OutputStream out, boolean closeIS, boolean closeOS) throws IOException {
085        try {
086            copy(in,out,0xffff);
087        }
088        finally {
089            if(closeIS)closeEL(in);
090            if(closeOS)closeEL(out);
091        }
092    }
093    
094    /**
095     * copy a inputstream to a outputstream
096     * @param in 
097     * @param out
098     * @param closeIS 
099     * @param closeOS 
100     * @throws IOException
101     */
102    public static final void merge(InputStream in1, InputStream in2, OutputStream out, boolean closeIS1, boolean closeIS2, boolean closeOS) throws IOException {
103        try {
104            merge(in1,in2,out,0xffff);
105        }
106        finally {
107            if(closeIS1)closeEL(in1);
108            if(closeIS2)closeEL(in2);
109            if(closeOS)closeEL(out);
110        }
111    }
112    
113    /**
114     * copy a inputstream to a outputstream
115     * @param in 
116     * @param out
117     * @param closeIS 
118     * @param closeOS 
119     * @throws IOException
120     */
121    public static final void copy(OutputStream out, InputStream in,boolean closeIS, boolean closeOS) throws IOException {
122        copy(in,out,closeIS,closeOS);
123    }
124    
125        /**
126         * copy a input resource to a output resource
127     * @param in
128         * @param out
129         * @throws IOException
130         */
131        public static void copy(Resource in, Resource out) throws IOException {
132                in.copyTo(out, false);
133        }
134        
135        public static void merge(Resource in1, Resource in2, Resource out) throws IOException {
136                InputStream is1=null;
137                InputStream is2=null;
138                OutputStream os=null;
139                try {
140                        is1=toBufferedInputStream(in1.getInputStream());
141                        is2=toBufferedInputStream(in2.getInputStream());
142                        os=toBufferedOutputStream(out.getOutputStream());
143                }
144                catch(IOException ioe) {
145                        IOUtil.closeEL(is1);
146                        IOUtil.closeEL(is2);
147                        IOUtil.closeEL(os);
148                        throw ioe;
149                }
150                merge(is1,is2,os,true,true,true);
151        }
152
153        /**
154         * copy a input resource to a output resource
155     * @param in
156         * @param out
157         * @throws IOException
158         */
159        public static void copy(InputStream is, Resource out, boolean closeIS) throws IOException {
160                OutputStream os=null;
161                try {
162                        os=toBufferedOutputStream(out.getOutputStream());
163                }
164                catch(IOException ioe) {
165                        IOUtil.closeEL(os);
166                        throw ioe;
167                }
168                copy(is,os,closeIS,true);
169        }
170    
171        /**
172         * copy a input resource to a output resource
173     * @param in
174         * @param out
175         * @throws IOException
176         */
177        public static void copy(Resource in, OutputStream os, boolean closeOS) throws IOException {
178                InputStream is=null;
179                try {
180                        is=toBufferedInputStream(in.getInputStream());
181                }
182                catch(IOException ioe) {
183                        IOUtil.closeEL(is);
184                        throw ioe;
185                }
186                copy(is,os,true,closeOS);
187        }
188    
189    public static final void copy(InputStream in, OutputStream out, int offset, int length) throws IOException {
190        copy(in, out, offset, length,0xffff);
191    }
192    
193    public static final void copy(InputStream in, OutputStream out, long offset, long length) throws IOException {
194        int len;
195        byte[] buffer;
196        int block=0xffff;
197        
198        // first offset to start
199        if(offset>0) {
200                long skipped=0;
201                try{
202                        skipped = in.skip(offset);
203                }
204                catch(Throwable t){
205                ExceptionUtil.rethrowIfNecessary(t);
206            }
207                
208                        if(skipped<=0) {
209                        while(true) {
210                        if(block>offset)block=(int)offset;
211                        buffer = new byte[block];
212                        len = in.read(buffer);
213                        if(len==-1) throw new IOException("reading offset is bigger than input itself");
214                        //dnos.write(buffer, 0, len);
215                        offset-=len;
216                        if(offset<=0) break;
217                    }
218                }
219        }
220        
221        // write part
222        if(length<0) {
223                copy(in, out,block);
224                return;
225        }
226        
227        while(true) {
228                if(block>length)block=(int) length;
229                buffer = new byte[block];
230                len = in.read(buffer);
231                if(len==-1) break;
232                out.write(buffer, 0, len);
233                length-=len;
234                if(length<=0) break;
235        }
236    }
237    
238    public static final void copy(InputStream in, OutputStream out, int offset, int length, int blockSize) throws IOException {
239
240        int len;
241        byte[] buffer;
242        int block;//0xffff;
243        
244        // first offset to start
245        if(offset>0) {
246                long skipped=0;
247                try{
248                        skipped = in.skip(offset);
249                }
250                catch(Throwable t){
251                ExceptionUtil.rethrowIfNecessary(t);
252            }
253                
254                        if(skipped<=0) {
255                        block = blockSize;//0xffff;
256                        while(true) {
257                        if(block>offset)block=offset;
258                        buffer = new byte[block];
259                        len = in.read(buffer);
260                        if(len==-1) throw new IOException("reading offset is bigger than input itself");
261                        //dnos.write(buffer, 0, len);
262                        offset-=len;
263                        if(offset<=0) break;
264                    }
265                        }
266        }
267        
268        // write part
269        if(length<0) {
270                copy(in, out,blockSize);
271                return;
272        }
273        block = blockSize;//0xffff;
274        while(true) {
275                if(block>length)block=length;
276                buffer = new byte[block];
277                len = in.read(buffer);
278                if(len==-1) break;
279                out.write(buffer, 0, len);
280                length-=len;
281                if(length<=0) break;
282        }
283    }
284
285        /**
286     * copy a inputstream to a outputstream
287     * @param in 
288     * @param out
289     * @param blockSize 
290     * @throws IOException
291     */
292    private static final void copy(InputStream in, OutputStream out, int blockSize) throws IOException {
293        byte[] buffer = new byte[blockSize];
294        int len;
295        while((len = in.read(buffer)) !=-1) {
296          out.write(buffer, 0, len);
297        }
298    }
299    
300    private static final void merge(InputStream in1, InputStream in2, OutputStream out, int blockSize) throws IOException {
301        copy(in1, out,blockSize);
302        copy(in2, out,blockSize);
303    }
304    
305    /**
306     * copy a reader to a writer
307     * @param r 
308     * @param w 
309     * @throws IOException
310     */
311    private static final void copy(Reader r, Writer w, long timeout) throws IOException {
312        copy(r,w,0xffff,timeout);
313    }
314    
315    /**
316     * copy a reader to a writer
317     * @param reader 
318     * @param writer 
319     * @param closeReader 
320     * @param closeWriter 
321     * @throws IOException
322     */
323    public static final void copy(Reader reader, Writer writer, boolean closeReader, boolean closeWriter) throws IOException {
324        try {
325            copy(reader,writer,0xffff,-1);
326        }
327        finally {
328            if(closeReader)closeEL(reader);
329            if(closeWriter)closeEL(writer);
330        }
331    }
332    
333    /**
334     * copy a reader to a writer
335     * @param r 
336     * @param w 
337     * @param blockSize 
338     * @throws IOException
339     */
340    private static final void copy(Reader r, Writer w, int blockSize, long timeout) throws IOException {
341        if(timeout<1) {
342                char[] buffer = new char[blockSize];
343                int len;
344        
345                while((len = r.read(buffer)) !=-1)
346                  w.write(buffer, 0, len);
347        }
348        else {
349                Copy c=new Copy(r, w, blockSize, timeout);
350                c.start();
351                
352                        try {
353                                synchronized(c.notifier){//print.err(timeout);
354                                        c.notifier.wait(timeout+1);
355                                }
356                        } 
357                        catch (InterruptedException ie) {
358                                throw ExceptionUtil.toIOException(c.t);
359                        }
360                        if(c.t!=null) throw ExceptionUtil.toIOException(c.t);
361                        if(!c.finished) throw new IOException("reached timeout ("+timeout+"ms) while copying data");
362                
363        }
364    }
365    
366    /** 
367     * copy content of in file to out File 
368     * @param in input 
369     * @param out output 
370     * @throws IOException 
371     */ 
372    public void copy(File in,File out) throws IOException {
373        InputStream is=null;
374        OutputStream os=null;
375                try {
376                        is = new BufferedFileInputStream(in);
377                        os = new BufferedFileOutputStream(out);
378                } 
379                catch (IOException ioe) {
380                        closeEL(is,os);
381                        throw ioe;
382                }
383        copy(is,os,true,true); 
384    } 
385
386    
387    
388    
389
390    /**
391     * close inputstream without a Exception
392     * @param is 
393     * @param os 
394     */
395     public static void closeEL(InputStream is, OutputStream os) {
396          closeEL(is);
397          closeEL(os);
398      }
399     
400    /**
401     * close inputstream without a Exception
402     * @param is 
403     */
404     public static void closeEL(InputStream is) {
405         try {
406                 if(is!=null)is.close();
407         } 
408         //catch (AlwaysThrow at) {throw at;}
409         catch (Throwable t) {
410                ExceptionUtil.rethrowIfNecessary(t);
411         }
412     }
413     
414     public static void closeEL(ZipFile zip) {
415         try {
416                 if(zip!=null)zip.close();
417         } 
418         //catch (AlwaysThrow at) {throw at;}
419         catch (Throwable t) {
420                ExceptionUtil.rethrowIfNecessary(t);
421         }
422     }
423     
424     /**
425      * close outputstream without a Exception
426      * @param os 
427      */
428     public static void closeEL(OutputStream os) {
429           try {
430               if(os!=null)os.close();
431         } 
432         //catch (AlwaysThrow at) {throw at;}
433         catch (Throwable t) {
434                ExceptionUtil.rethrowIfNecessary(t);
435         }
436       }
437     
438     public static void closeEL(ResultSet rs) {
439         try {
440             if(rs!=null)rs.close();
441       } 
442       catch (Throwable t) {
443        ExceptionUtil.rethrowIfNecessary(t);
444       }
445     }
446     
447     /**
448      * close Reader without a Exception
449      * @param r 
450      */
451     public static void closeEL(Reader r) {
452           try {
453               if(r!=null)r.close();
454         } 
455         //catch (AlwaysThrow at) {throw at;}
456         catch (Throwable t) {
457                ExceptionUtil.rethrowIfNecessary(t);
458         }
459       }
460
461     
462     /**
463      * close Closeable without a Exception
464      * @param r 
465      */
466     public static void closeEL(Closeable c ) {
467           try {
468               if(c!=null)c.close();
469         } 
470         //catch (AlwaysThrow at) {throw at;}
471         catch (Throwable t) {
472                ExceptionUtil.rethrowIfNecessary(t);
473         }
474       }
475     
476     /**
477      * close Writer without a Exception
478      * @param w 
479      */
480     public static void closeEL(Writer w) {
481         try {
482               if(w!=null)w.close();
483         } 
484         //catch (AlwaysThrow at) {throw at;}
485         catch (Throwable t) {
486                ExceptionUtil.rethrowIfNecessary(t);
487         }
488     }
489     
490     /**
491      * close Writer without a Exception
492      * @param w 
493      */
494     public static void closeEL(Transport t) {
495           try {
496               if(t!=null && t.isConnected())t.close();
497         } 
498         catch (Throwable e) {
499                ExceptionUtil.rethrowIfNecessary(e);
500         }
501     }
502     
503
504     public static void closeEL(Document doc) {
505           try {
506               if(doc!=null)doc.close();
507         } 
508         catch (Throwable t) {
509                ExceptionUtil.rethrowIfNecessary(t);
510         }
511     }
512     
513     public static void closeEL(Connection conn) {
514         try {
515             if(conn!=null)conn.close();
516       } 
517       catch (Throwable t) {
518        ExceptionUtil.rethrowIfNecessary(t);
519       }
520   }
521     
522     
523     
524     /**
525     * call close method from any Object with a close method.
526     * @param obj
527     */
528     public static void closeEL(Object obj) {
529         if(obj instanceof InputStream)         IOUtil.closeEL((InputStream)obj);
530         else if(obj instanceof OutputStream)   IOUtil.closeEL((OutputStream)obj);
531         else if(obj instanceof Writer)         IOUtil.closeEL((Writer)obj);
532         else if(obj instanceof Reader)         IOUtil.closeEL((Reader)obj);
533         else if(obj instanceof Closeable)         IOUtil.closeEL((Closeable)obj);
534         else if(obj instanceof ZipFile)        IOUtil.closeEL((ZipFile)obj);
535         else if(obj instanceof ResultSet)        IOUtil.closeEL((ResultSet)obj);
536         else {
537             try {
538                 Method method = obj.getClass().getMethod("close",new Class[0]);
539                 method.invoke(obj,new Object[0]);
540             } 
541             catch (Throwable t) {
542                ExceptionUtil.rethrowIfNecessary(t);
543             }
544         }
545     }
546
547    /**
548     * @deprecated use instead <code>{@link #getReader(Resource, Charset)}</code>
549     * @param res
550     * @param charset
551     * @return
552     * @throws IOException
553     */
554        public static Reader getReader(Resource res, String charset) throws IOException {
555                return getReader(res, CharsetUtil.toCharset(charset));
556        }
557        
558        public static Reader getReader(Resource res, Charset charset) throws IOException {
559                /*
560                00 00 FE FF     UTF-32, big-endian
561                FF FE 00 00     UTF-32, little-endian
562                */
563                
564                
565                InputStream is=null;
566                try {
567                        is = res.getInputStream();
568                        boolean markSupported=is.markSupported();
569                if(markSupported) is.mark(4);
570                int first = is.read();
571                int second = is.read();
572                // FE FF        UTF-16, big-endian
573                if (first == 0xFE && second == 0xFF)    {
574                        return _getReader(is, CharsetUtil.UTF16BE);
575                }
576                // FF FE        UTF-16, little-endian
577                if (first == 0xFF && second == 0xFE)    {
578                        return _getReader(is, CharsetUtil.UTF16LE);
579                }
580                
581                int third=is.read();
582                // EF BB BF     UTF-8
583                if (first == 0xEF && second == 0xBB && third == 0xBF)    {
584                        //is.reset();
585                                return _getReader(is,CharsetUtil.UTF8);
586                }
587                        /*
588                int forth=is.read();
589                // 00 00 FE FF          UTF-32, big-endian
590                if (first == 0x00 && second == 0x00 && third == 0xFE  && forth == 0xFF)    {
591                        is.reset();
592                                return _getReader(is, "utf-32");
593                }
594                // FF FE 00 00  UTF-32, little-endian
595                if (first == 0xFF && second == 0xFE && third == 0x00  && forth == 0x00)    {
596                        is.reset();
597                                return _getReader(is, "utf-32");
598                }*/
599                
600                if(markSupported) {
601                        is.reset();
602                        return _getReader(is,charset);
603                }
604                }
605                catch(IOException ioe) {
606                        IOUtil.closeEL(is);
607                        throw ioe;
608                }
609                
610        // when mark not supported return new reader
611        closeEL(is);
612        is=null;
613                try {
614                        is=res.getInputStream();
615                }
616                catch(IOException ioe) {
617                        closeEL(is);
618                        throw ioe;
619                }
620        return _getReader(is, charset);             
621   }
622
623        public static Reader getReader(InputStream is, Charset charset) throws IOException {
624                        
625                        boolean markSupported=is.markSupported();
626                if(!markSupported) return _getReader(is, charset);
627                
628                if(markSupported) is.mark(4);
629                
630                int first = is.read();
631                int second = is.read();
632                // FE FF        UTF-16, big-endian
633                if (first == 0xFE && second == 0xFF)    {
634                        //is.reset();
635                                return _getReader(is, CharsetUtil.UTF16BE);
636                }
637                // FF FE        UTF-16, little-endian
638                if (first == 0xFF && second == 0xFE)    {
639                        // TODO FF FE 00 00 UTF-32 little-endian
640                                return _getReader(is, CharsetUtil.UTF16LE);
641                }
642                
643                int third=is.read();
644                // EF BB BF     UTF-8
645                if (first == 0xEF && second == 0xBB && third == 0xBF)    {
646                        return _getReader(is, CharsetUtil.UTF8);
647                }
648                
649                // 00 00 FE FF UTF-32 big-endian
650                int forth=is.read();
651                if (first == 0x00 && second == 0x00 && third == 0xFE && forth == 0xFF)    {
652                        return _getReader(is, CharsetUtil.UTF32BE);
653                }
654                
655
656                        is.reset();
657                return _getReader(is,charset);       
658           }
659                
660        /**
661         * @deprecated use instead <code>{@link #getReader(InputStream, Charset)}</code>
662         * @param is
663         * @param charset
664         * @return
665         * @throws IOException
666         */
667        public static Reader getReader(InputStream is, String charset) throws IOException {
668                return getReader(is, CharsetUtil.toCharset(charset));    
669    }
670         
671     /**
672      * returns a Reader for the given InputStream
673      * @param is
674      * @param charset
675      * @return Reader
676      * @throws IOException
677      */
678         private static Reader _getReader(InputStream is, Charset charset) throws IOException {
679                 if(charset==null) charset=SystemUtil.getCharset();
680             return new BufferedReader(new InputStreamReader(is,charset));
681         }
682
683    /**
684     * @deprecated use instead <code>{@link #toString(InputStream, Charset)}</code>
685     * @param is
686     * @param charset
687     * @return
688     * @throws IOException
689     */
690     public static String toString(InputStream is, String charset) throws IOException {
691         return toString(is,CharsetUtil.toCharset(charset));
692     }
693     
694     /**
695     * reads string data from a InputStream
696     * @param is
697     * @param charset 
698     * @return string from inputstream
699    * @throws IOException 
700    */
701     public static String toString(InputStream is, Charset charset) throws IOException {
702         return toString(getReader(is,charset));
703     }
704     
705     /**
706     * reads string data from a InputStream
707     * @param is
708     * @param charset 
709     * @param timeout in milliseconds 
710     * @return string from inputstream
711    * @throws IOException 
712    */
713     public static String toString(InputStream is, Charset charset, long timeout) throws IOException {
714         return toString(getReader(is,charset),timeout);
715     }
716     
717     /**
718      * @deprecated use instead <code>{@link #toString(byte[], Charset)}</code>
719      * @param barr
720      * @param charset
721      * @return
722      * @throws IOException
723      */
724     public static String toString(byte[] barr, String charset) throws IOException {
725         return toString(barr,CharsetUtil.toCharset(charset));
726     }
727     
728     public static String toString(byte[] barr, Charset charset) throws IOException {
729         return toString(getReader(new ByteArrayInputStream(barr),charset));
730     }
731
732     
733     /**
734      * reads String data from a Reader
735      * @param reader
736      * @return readed string
737      * @throws IOException
738      */
739     public static String toString(Reader reader) throws IOException {
740         return toString(reader,-1);
741     }
742     
743   /**
744    * reads String data from a Reader
745    * @param reader
746    * @param timeout timeout in milliseconds
747    * @return readed string
748    * @throws IOException
749    */
750   public static String toString(Reader reader, long timeout) throws IOException {
751       StringWriter sw=new StringWriter(512);
752       copy(toBufferedReader(reader),sw,timeout);
753       sw.close();
754       return sw.toString();
755   }
756
757   /**
758    * reads String data from a Reader
759    * @param reader
760    * @return readed string
761    * @throws IOException
762    */
763   public static String toString(Reader reader,boolean buffered) throws IOException {
764       StringWriter sw=new StringWriter(512);
765       if(buffered)copy(toBufferedReader(reader),sw,-1);
766       else copy(reader,sw,-1);
767       sw.close();
768       return sw.toString();
769   }
770
771   /**
772    * @deprecated use instead <code>{@link #toString(Resource, Charset)}</code>
773    * @param file
774    * @param charset
775    * @return
776    * @throws IOException
777    */
778   public static String toString(Resource file, String charset) throws IOException {
779           return toString(file, CharsetUtil.toCharset(charset));
780   }
781   
782   /**
783    * reads String data from File
784     * @param file 
785     * @param charset 
786     * @return readed string
787    * @throws IOException
788    */
789   public static String toString(Resource file, Charset charset) throws IOException {
790       Reader r = null;
791       try {
792           r = getReader(file,charset);
793           String str = toString(r);
794           return str;
795       }
796       finally {
797           closeEL(r);
798       }
799   }
800
801    /**
802     * @param reader Reader to get content from it
803     * @return returns the content of the file as String Array (Line by Line)
804     * @throws IOException
805     */
806    public static String[] toStringArray(Reader reader) throws IOException {
807        if(reader==null)return new String[0];
808        BufferedReader br = new BufferedReader(reader); 
809        LinkedList<String> list=new LinkedList<String>();
810        
811        String line;
812        while((line=br.readLine())!=null)   {
813            list.add(line);
814        }
815        br.close();
816        String[] content=new String[list.size()];
817        int count=0;
818        while(!list.isEmpty()) {
819            content[count++]=list.removeFirst();
820        }
821        return content;
822    }
823
824    /**
825     * @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code> 
826     * writes a String to a object
827     * @param file 
828     * @param string String to write to file
829     * @param charset
830     * @param append  append to cuuretn data or overwrite existing data
831     * @throws IOException
832     */
833    public static void write(File file, String string, String strCharset, boolean append) throws IOException {
834        Charset charset;
835        if(StringUtil.isEmpty(strCharset)) {
836            charset=SystemUtil.getCharset();
837        }  
838        else charset=CharsetUtil.toCharset(strCharset);
839                
840        OutputStreamWriter writer=null;
841        try {
842            writer=new OutputStreamWriter(new BufferedFileOutputStream(file,append),charset);
843            writer.write(string);
844            
845        }
846        finally {
847            closeEL(writer);
848        }
849    }
850    
851    /**
852     * @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code>
853     * @param res
854     * @param string
855     * @param charset
856     * @param append
857     * @throws IOException
858     */
859    public static void write(Resource res, String string, String charset, boolean append) throws IOException {
860        write(res, string, CharsetUtil.toCharset(charset), append);
861    }
862    
863    public static void write(Resource res, String string, Charset charset, boolean append) throws IOException {
864        if(charset==null) {
865            charset=SystemUtil.getCharset();
866        }
867                
868        
869        Writer writer=null;
870        try {
871            writer=getWriter(res, charset,append);
872            writer.write(string);
873        }
874        finally {
875            closeEL(writer);
876        }
877    }
878
879
880    public static void write(Resource res, byte[] barr) throws IOException {
881        ByteArrayInputStream bais = new ByteArrayInputStream(barr);
882        OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream());
883        IOUtil.copy(bais, os, true, true);
884    }
885
886    public static void write(Resource res, byte[] barr, boolean append) throws IOException {
887        ByteArrayInputStream bais = new ByteArrayInputStream(barr);
888        OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream(append));
889        IOUtil.copy(bais, os, true, true);
890    }
891    
892    /**
893     * @deprecated use instead <code>{@link #toBytes(Resource)}</code> 
894     * @param file 
895     * @return returns the Content of the file as byte array
896     * @throws IOException
897     */
898    public static byte[] toBytes(File file) throws IOException {
899        BufferedFileInputStream bfis = null;
900        try {
901                bfis = new BufferedFileInputStream(file);
902            byte[] barr = toBytes(bfis);
903            return barr;
904        }
905        finally {
906            closeEL(bfis);
907        }
908    }
909    
910    /**
911     * @param res 
912     * @return returns the Content of the file as byte array
913     * @throws IOException
914     */
915    public static byte[] toBytes(Resource res) throws IOException {
916        BufferedInputStream bfis = null;
917        try {
918                bfis = toBufferedInputStream(res.getInputStream());
919            byte[] barr = toBytes(bfis);
920            return barr;
921        }
922        finally {
923            closeEL(bfis);
924        }
925    }
926
927    public static BufferedInputStream toBufferedInputStream(InputStream is) {
928                if(is instanceof BufferedInputStream) return (BufferedInputStream) is;
929                return new BufferedInputStream(is);
930        }
931    
932    public static BufferedOutputStream toBufferedOutputStream(OutputStream os) {
933                if(os instanceof BufferedOutputStream) return (BufferedOutputStream) os;
934                return new BufferedOutputStream(os);
935        }
936    
937    public static BufferedReader toBufferedReader(Reader r) {
938                if(r instanceof BufferedReader) return (BufferedReader) r;
939                return new BufferedReader(r);
940        }
941
942    /**
943     * @deprecated use instead <code>{@link #getBufferedReader(Resource, Charset)}</code>
944     * @param res
945     * @param charset
946     * @return
947     * @throws IOException
948     */
949    public static BufferedReader getBufferedReader(Resource res,String charset) throws IOException {
950                return getBufferedReader(res,CharsetUtil.toCharset(charset));
951        }
952    
953    public static BufferedReader getBufferedReader(Resource res,Charset charset) throws IOException {
954                return toBufferedReader(getReader(res, charset));
955        }
956    
957    
958    public static BufferedWriter toBufferedWriter(Writer w) {
959                if(w instanceof BufferedWriter) return (BufferedWriter) w;
960                return new BufferedWriter(w);
961        }
962
963        /**
964     * @param is 
965     * @return returns the Content of the file as byte array
966     * @throws IOException
967     */
968    public static byte[] toBytes(InputStream is) throws IOException {
969       return toBytes(is,false);
970    }
971    
972
973    public static byte[] toBytes(InputStream is, boolean closeStream) throws IOException {
974        ByteArrayOutputStream baos = new ByteArrayOutputStream();
975        copy(is,baos,closeStream,true);
976        return baos.toByteArray();
977    }
978
979    public static byte[] toBytesMax(InputStream is, int max) throws IOException {
980        ByteArrayOutputStream baos = new ByteArrayOutputStream();
981        copy(is,baos,0,max);
982        return baos.toByteArray();
983    }
984
985    /**
986     * flush OutputStream without a Exception
987     * @param os
988     */
989    public static void flushEL(OutputStream os) {
990        try {
991            if(os!=null)os.flush();
992        } catch (Exception e) {}
993    }
994
995    /**
996     * flush OutputStream without a Exception
997     * @param os
998     */
999    public static void flushEL(Writer w) {
1000        try {
1001            if(w!=null)w.flush();
1002        } catch (Exception e) {}
1003    }
1004    
1005    /**
1006     * check if given encoding is ok
1007     * @param encoding
1008     * @throws PageException 
1009     */
1010    public static void checkEncoding(String encoding) throws IOException {
1011                try {
1012                        URLEncoder.encode("", encoding);
1013                } catch (UnsupportedEncodingException e) {
1014                        throw new IOException("invalid encoding ["+encoding+"]");
1015                }
1016        }
1017    
1018    /**
1019     * return the mime type of a file, dont check extension
1020     * @param barr
1021     * @param defaultValue 
1022     * @return mime type of the file
1023     */
1024    public static String getMimeType(InputStream is, String defaultValue) {
1025        try {
1026                        return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
1027                } catch (IOException e) {
1028                        return defaultValue;
1029                }
1030        
1031        
1032        /*try {
1033                        return URLConnection.guessContentTypeFromStream(is);
1034                } catch (Throwable t) {
1035                ExceptionUtil.rethrowIfNecessary(t);
1036                        return defaultValue;
1037                }*/
1038                
1039        /*try {
1040                        return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
1041                } catch (IOException e) {
1042                        return defaultValue;
1043                }*/
1044    }
1045    
1046    
1047    /**
1048     * return the mime type of a file, dont check extension
1049     * @param barr
1050     * @return mime type of the file
1051     * @throws IOException 
1052     */
1053    public static String getMimeType(byte[] barr, String defaultValue) {
1054        
1055        //String mt = getMimeType(new ByteArrayInputStream(barr), null);
1056        //if(!StringUtil.isEmpty(mt,true)) return mt;
1057        
1058        PrintStream out = System.out;
1059        try {
1060                System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM));
1061            MagicMatch match = Magic.getMagicMatch(barr);
1062            return match.getMimeType();
1063        } 
1064        catch (Throwable t) {
1065                ExceptionUtil.rethrowIfNecessary(t);
1066                        return defaultValue;
1067        }
1068        finally {
1069                System.setOut(out);
1070        }
1071    }
1072    
1073    /**
1074     * @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code>
1075     * @param res
1076     * @param charset
1077     * @return
1078     * @throws IOException
1079     */
1080    public static Writer getWriter(Resource res, String charset) throws IOException {
1081        return getWriter(res, CharsetUtil.toCharset(charset));
1082    }
1083    
1084        public static Writer getWriter(Resource res, Charset charset) throws IOException {
1085                OutputStream os=null;
1086                try {
1087                        os=res.getOutputStream();
1088                }
1089                catch(IOException ioe) {
1090                        closeEL(os);
1091                        throw ioe;
1092                }
1093                return getWriter(os, charset);
1094         
1095        }
1096        
1097        /**
1098         * @deprecated use instead <code>{@link #getWriter(Resource, Charset,boolean)}</code>
1099         * @param res
1100         * @param charset
1101         * @param append
1102         * @return
1103         * @throws IOException
1104         */
1105        public static Writer getWriter(Resource res, String charset, boolean append) throws IOException {
1106                return getWriter(res, CharsetUtil.toCharset(charset), append);
1107        }
1108        
1109        public static Writer getWriter(Resource res, Charset charset, boolean append) throws IOException {
1110                OutputStream os=null;
1111                try {
1112                        os=res.getOutputStream(append);
1113                }
1114                catch(IOException ioe) {
1115                        closeEL(os);
1116                        throw ioe;
1117                }
1118                return getWriter(os, charset);
1119        }
1120    
1121    /**
1122     * @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code> 
1123     * returns a Reader for the given File and charset (Automaticly check BOM Files)
1124     * @param file
1125     * @param charset
1126     * @return Reader
1127     * @throws IOException
1128     */
1129    public static Writer getWriter(File file, String charset) throws IOException {
1130        OutputStream os=null;
1131                try {
1132                        os=new FileOutputStream(file);
1133                }
1134                catch(IOException ioe) {
1135                        closeEL(os);
1136                        throw ioe;
1137                }
1138                return getWriter(os, charset);
1139   }
1140    
1141    /**
1142     * @deprecated use instead <code>{@link #getWriter(Resource, Charset, boolean)}</code> 
1143     * returns a Reader for the given File and charset (Automaticly check BOM Files)
1144     * @param file
1145     * @param charset
1146     * @return Reader
1147     * @throws IOException
1148     */
1149    public static Writer getWriter(File file, String charset, boolean append) throws IOException {
1150        OutputStream os=null;
1151                try {
1152                        os=new FileOutputStream(file,append);
1153                }
1154                catch(IOException ioe) {
1155                        closeEL(os);
1156                        throw ioe;
1157                }
1158                return getWriter(os, charset);
1159   }
1160     
1161    
1162    /**
1163     * @deprecated use instead <code>{@link #getWriter(OutputStream, Charset)}</code>
1164     * @param os
1165     * @param charset
1166     * @return
1167     * @throws IOException
1168     */
1169    public static Writer getWriter(OutputStream os, String charset) throws IOException {
1170        return getWriter(os, CharsetUtil.toCharset(charset));
1171    }
1172    
1173    /**
1174     * returns a Reader for the given InputStream
1175     * @param is
1176     * @param charset
1177     * @return Reader
1178     * @throws IOException
1179     */
1180    public static Writer getWriter(OutputStream os, Charset charset) throws IOException {
1181         if(charset==null) charset=SystemUtil.getCharset();
1182        return new BufferedWriter(new OutputStreamWriter(os,charset));
1183    }
1184
1185        public static String read(Reader reader, int size) throws IOException {
1186                return read(reader, new char[size]);
1187        }
1188        
1189        public static String read(Reader reader,char[] carr) throws IOException {
1190                int rst = reader.read(carr);
1191                if(rst==-1)return null;
1192                return new String(carr,0,rst);
1193        }
1194        
1195
1196        private static class Copy extends Thread {
1197        
1198                private Reader r;
1199                private Writer w;
1200                private int blockSize;
1201                private long timeout;
1202                private boolean finished;
1203                private Throwable t;
1204                private Object notifier=new Object();
1205
1206                private Copy(Reader r, Writer w, int blockSize, long timeout) {
1207                        this.r=r;
1208                        this.w=w;
1209                        this.blockSize=blockSize;
1210                        this.timeout=timeout;
1211                }
1212                
1213                @Override
1214                public void run(){
1215                        try {
1216                                IOUtil.copy(r, w, blockSize, -1);
1217                        } 
1218                        catch(Throwable t) {
1219                ExceptionUtil.rethrowIfNecessary(t);
1220                                this.t=t;
1221                        }
1222                        finally {
1223                                finished=true;
1224                                SystemUtil.notify(notifier);
1225                        }
1226                }
1227        }
1228}
1229