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.loader.util;
020
021import java.io.BufferedInputStream;
022import java.io.BufferedOutputStream;
023import java.io.BufferedReader;
024import java.io.File;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.InputStreamReader;
028import java.io.OutputStream;
029import java.io.Reader;
030import java.io.Writer;
031import java.text.SimpleDateFormat;
032import java.util.Date;
033import java.util.Locale;
034import java.util.StringTokenizer;
035import java.util.TimeZone;
036
037import lucee.commons.io.res.Resource;
038
039/**
040 * Util class for different little jobs
041 */
042public class Util {
043    
044    private static File tempFile;
045    private static File homeFile;
046    
047    private final static SimpleDateFormat HTTP_TIME_STRING_FORMAT;
048        static {
049                HTTP_TIME_STRING_FORMAT = new SimpleDateFormat("EE, dd MMM yyyy HH:mm:ss zz",Locale.ENGLISH);
050                HTTP_TIME_STRING_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
051        }
052    
053
054    /**
055     * copy a inputstream to a outputstream
056     * @param in 
057     * @param out
058     * @throws IOException
059     */
060    public final static void copy(InputStream in, OutputStream out) throws IOException {
061        byte[] buffer = new byte[0xffff];
062        int len;
063        while((len = in.read(buffer)) !=-1)
064          out.write(buffer, 0, len);
065        
066        closeEL(in);
067        closeEL(out);
068    }
069    
070    public final static void copy(InputStream in, OutputStream out, boolean closeIS, boolean closeOS) throws IOException {
071        byte[] buffer = new byte[0xffff];
072        int len;
073        while((len = in.read(buffer)) !=-1)
074          out.write(buffer, 0, len);
075        
076        if(closeIS)closeEL(in);
077        if(closeOS)closeEL(out);
078    }
079    
080    /**
081     * read String data from a InputStream and returns it as String Object 
082     * @param is InputStream to read data from.
083     * @return readed data from InputStream
084     * @throws IOException
085     */
086    public static String toString(InputStream is) throws IOException {
087        BufferedReader br = new BufferedReader(new InputStreamReader(is)); 
088        StringBuffer content=new StringBuffer();
089        
090        String line=br.readLine();
091        if(line!=null) {
092            content.append(line);
093            while((line=br.readLine())!=null)   {
094                content.append("\n"+line);
095            }
096        }
097        br.close();
098        return content.toString();
099    }
100    
101
102        public static boolean toBooleanValue(String str) throws IOException {
103                str=str.trim().toLowerCase();
104
105                if("true".equals(str)) return true;
106                if("false".equals(str)) return false;
107                if("yes".equals(str)) return true;
108                if("no".equals(str)) return false;
109                throw new IOException("can't cast string to a boolean value");
110        }
111    
112
113    /**
114     * close inputstream without a Exception
115     * @param is 
116     * @param os 
117     */
118     public static void closeEL(InputStream is,OutputStream os) {
119         closeEL(is);
120         closeEL(os);
121      }
122
123     /**
124      * close inputstream without a Exception
125      * @param is 
126      */
127      public static void closeEL(InputStream is) {
128           try {
129             if(is!=null)is.close();
130         } 
131         catch (Throwable e) {
132                                if(e instanceof ThreadDeath) throw (ThreadDeath)e;}
133       }
134
135      /**
136       * close reader without a Exception
137       * @param is 
138       */
139       public static void closeEL(Reader r) {
140            try {
141              if(r!=null)r.close();
142          } 
143          catch (Throwable e) {
144                                if(e instanceof ThreadDeath) throw (ThreadDeath)e;}
145        }
146
147       /**
148        * close reader without a Exception
149        * @param is 
150        */
151        public static void closeEL(Writer w) {
152           try {
153               if(w!=null)w.close();
154           } 
155           catch (Throwable t) {
156                                if(t instanceof ThreadDeath) throw (ThreadDeath)t;}
157         }
158
159     
160     /**
161      * close outputstream without a Exception
162      * @param os 
163      */
164     public static void closeEL(OutputStream os) {
165           try {
166               if(os!=null)os.close();
167         } 
168         catch (Throwable t) {
169                                if(t instanceof ThreadDeath) throw (ThreadDeath)t;}
170       }
171     
172    /**
173     * @param is inputStream to get content From
174     * @param charset
175     * @return returns content from a file inputed by input stream
176     * @throws IOException
177     */
178    public static String getContentAsString(InputStream is, String charset) throws IOException {
179    
180        BufferedReader br = (charset==null)?
181                new BufferedReader(new InputStreamReader(is)):
182                new BufferedReader(new InputStreamReader(is,charset)); 
183        StringBuffer content=new StringBuffer();
184        
185        String line=br.readLine();
186        if(line!=null) {
187            content.append(line);
188            while((line=br.readLine())!=null)   {
189                content.append("\n"+line);
190            }
191        }
192        br.close();
193        return content.toString();
194     }
195
196    /**
197     * check if string is empty (null or "")
198     * @param str
199     * @return is empty or not
200     */
201    public static boolean isEmpty(String str) {
202        return str==null || str.length()==0;
203    }
204
205    /**
206     * check if string is empty (null or "")
207     * @param str
208     * @return is empty or not
209     */
210    public static boolean isEmpty(String str, boolean trim) {
211        if(!trim) return isEmpty(str);
212        return str==null || str.trim().length()==0;
213    }
214
215
216        public static int length(String str) {
217                if(str==null) return 0;
218                return str.length();
219        }
220        
221    /**
222     * cast a lucee string version to a int version
223     * @param version
224     * @return int version
225     */
226    public static int toInVersion(String version) {
227        
228        int     rIndex = version.lastIndexOf(".lco");
229        
230        if(rIndex!=-1) {
231            version=version.substring(0,rIndex);
232        }
233        
234        //1.0.0.090
235        int beginIndex=0;
236        
237        //Major
238        int endIndex=version.indexOf('.',beginIndex);
239        int intVersion=0;
240        intVersion+=Integer.parseInt(version.substring(beginIndex,endIndex))*1000000; // FUTURE 10000000
241
242        // Minor
243        beginIndex=endIndex+1;
244        endIndex=version.indexOf('.',beginIndex);
245        intVersion+=Integer.parseInt(version.substring(beginIndex,endIndex))*10000; // FUTURE 100000
246
247        // releases
248        beginIndex=endIndex+1;
249        endIndex=version.indexOf('.',beginIndex);
250        intVersion+=Integer.parseInt(version.substring(beginIndex,endIndex))*100; // FUTURE 1000
251        
252        // patches
253        beginIndex=endIndex+1;
254        intVersion+=Integer.parseInt(version.substring(beginIndex));
255        
256        return intVersion;
257        
258        
259        //intVersion=(major*1000000)+(minor*10000)+(releases*100)+patches;
260        
261    }
262    
263    public static String toStringVersion(int version) {
264        
265        StringBuffer sb=new StringBuffer();
266
267        // Major
268        int tmp=(version/1000000); // FUTURE 10000000
269        version-=tmp*1000000; // FUTURE 10000000
270        sb.append(String.valueOf(tmp));
271        sb.append(".");
272
273        // Minor
274        tmp=(version/10000); // FUTURE 100000
275        version-=tmp*10000; // FUTURE 100000
276        sb.append(len(String.valueOf(tmp),2));
277        sb.append(".");
278
279        // releases
280        tmp=(version/100); // FUTURE 1000
281        version-=tmp*100; // FUTURE 1000
282        sb.append(len(String.valueOf(tmp),2));
283        sb.append(".");
284        
285        // patches
286        sb.append(len(String.valueOf(version),3));
287        
288        return sb.toString();
289        
290    }
291    
292    
293    private static Object len(String str, int i) {
294                while(str.length()<i)
295                        str="0"+str;
296                return str;
297        }
298
299        /**
300     * @param str String to work with
301     * @param sub1 value to replace
302     * @param sub2 replacement
303     * @param onlyFirst replace only first or all 
304     * @return new String
305     */
306    public static String replace(String str, String sub1, String sub2, boolean onlyFirst) {
307        if(sub1.equals(sub2)) return str;
308        
309        if(!onlyFirst && sub1.length()==1 && sub2.length()==1)return str.replace(sub1.charAt(0),sub2.charAt(0));
310        
311        
312        StringBuffer sb=new StringBuffer();
313        int start=0;
314        int pos;
315        int sub1Length=sub1.length();
316        
317        while((pos=str.indexOf(sub1,start))!=-1){
318            sb.append(str.substring(start,pos));
319            sb.append(sub2);
320            start=pos+sub1Length;
321            if(onlyFirst)break;
322        }
323        sb.append(str.substring(start));
324        
325        return sb.toString();
326    }
327    /**
328     * replace path placeholder with the real path, placeholders are [{temp-directory},{system-directory},{home-directory}]
329     * @param path
330     * @return updated path
331     */
332    public static String parsePlaceHolder(String path) {
333        if(path==null) return path;
334        // Temp
335        if(path.startsWith("{temp")) {
336            if(path.startsWith("}",5)) path=new File(getTempDirectory(),path.substring(6)).toString();
337            else if(path.startsWith("-dir}",5)) path=new File(getTempDirectory(),path.substring(10)).toString();
338            else if(path.startsWith("-directory}",5)) path=new File(getTempDirectory(),path.substring(16)).toString();
339        }
340        // System
341        else if(path.startsWith("{system")) {
342            if(path.startsWith("}",7)) path=new File(getSystemDirectory(),path.substring(8)).toString();
343            else if(path.startsWith("-dir}",7)) path=new File(getSystemDirectory(),path.substring(12)).toString();
344            else if(path.startsWith("-directory}",7)) path=new File(getSystemDirectory(),path.substring(18)).toString();
345        }
346        // Home
347        else if(path.startsWith("{home")) {
348            if(path.startsWith("}",5)) path=new File(getHomeDirectory(),path.substring(6)).toString();
349            else if(path.startsWith("-dir}",5)) path=new File(getHomeDirectory(),path.substring(10)).toString();
350            else if(path.startsWith("-directory}",5)) path=new File(getHomeDirectory(),path.substring(16)).toString();
351        }
352        return path;
353    }
354    
355    /**
356     * returns the Temp Directory of the System
357     * @return temp directory
358     */
359    public static File getTempDirectory() {
360        if(tempFile!=null) return tempFile;
361        
362        String tmpStr = System.getProperty("java.io.tmpdir");
363        if(tmpStr!=null) {
364            tempFile=new File(tmpStr);
365            if(tempFile.exists()) {
366                tempFile=getCanonicalFileEL(tempFile);
367                return tempFile;
368            }
369        }
370        try {
371            File tmp = File.createTempFile("a","a");
372            tempFile=tmp.getParentFile();
373            tempFile=getCanonicalFileEL(tempFile);
374            tmp.delete();
375        }
376        catch(IOException ioe) {}
377        
378        return tempFile;
379    }
380    
381    /**
382     * returns the Hoome Directory of the System
383     * @return home directory
384     */
385    public static File getHomeDirectory() {
386        if(homeFile!=null) return homeFile;
387        
388        String homeStr = System.getProperty("user.home");
389        if(homeStr!=null) {
390            homeFile=new File(homeStr);
391            homeFile=getCanonicalFileEL(homeFile);
392        }
393        return homeFile;
394    }
395    
396
397    /**
398     * @return return System directory
399     */
400    public static File getSystemDirectory() {
401        String pathes=System.getProperty("java.library.path");
402        if(pathes!=null) {
403            String[] arr=pathes.split(File.pathSeparator);
404            //String[] arr=List.toStringArrayEL(List.listToArray(pathes,File.pathSeparatorChar));
405            for(int i=0;i<arr.length;i++) {    
406                if(arr[i].toLowerCase().indexOf("windows\\system")!=-1) {
407                    File file = new File(arr[i]);
408                    if(file.exists() && file.isDirectory() && file.canWrite()) return getCanonicalFileEL(file);
409                    
410                }
411            }
412            for(int i=0;i<arr.length;i++) {    
413                if(arr[i].toLowerCase().indexOf("windows")!=-1) {
414                    File file = new File(arr[i]);
415                    if(file.exists() && file.isDirectory() && file.canWrite()) return getCanonicalFileEL(file);
416                    
417                }
418            }
419            for(int i=0;i<arr.length;i++) {    
420                if(arr[i].toLowerCase().indexOf("winnt")!=-1) {
421                    File file = new File(arr[i]);
422                    if(file.exists() && file.isDirectory() && file.canWrite()) return getCanonicalFileEL(file);
423                    
424                }
425            }
426            for(int i=0;i<arr.length;i++) {    
427                if(arr[i].toLowerCase().indexOf("win")!=-1) {
428                    File file = new File(arr[i]);
429                    if(file.exists() && file.isDirectory() && file.canWrite()) return getCanonicalFileEL(file);
430                    
431                }
432            }
433            for(int i=0;i<arr.length;i++) {
434                File file = new File(arr[i]);
435                if(file.exists() && file.isDirectory() && file.canWrite()) return getCanonicalFileEL(file);
436            }
437        }
438        return null;
439    }
440    
441    /**
442     * Returns the canonical form of this abstract pathname.
443     * @param file file to get canoncial form from it
444     *
445     * @return  The canonical pathname string denoting the same file or
446     *          directory as this abstract pathname
447     *
448     * @throws  SecurityException
449     *          If a required system property value cannot be accessed.
450     */
451    public static File getCanonicalFileEL(File file) {
452        try {
453            return file.getCanonicalFile();
454        } catch (IOException e) {
455            return file;
456        }
457    }
458        
459        public static String toHTTPTimeString(Date date) {
460                return replace(HTTP_TIME_STRING_FORMAT.format(date),"+00:00","",true);
461        }
462        
463        public static String toHTTPTimeString() {
464                return replace(HTTP_TIME_STRING_FORMAT.format(new Date()),"+00:00","",true);
465        }
466        
467        public static boolean hasUpperCase(String str) {
468                if(isEmpty(str)) return false;
469                return !str.equals(str.toLowerCase());
470        }
471
472        public static BufferedInputStream toBufferedInputStream(InputStream is) {
473                if(is instanceof BufferedInputStream) return (BufferedInputStream) is;
474                return new BufferedInputStream(is);
475        }
476    
477    public static BufferedOutputStream toBufferedOutputStream(OutputStream os) {
478                if(os instanceof BufferedOutputStream) return (BufferedOutputStream) os;
479                return new BufferedOutputStream(os);
480        }
481
482    public static void copy(Resource in, Resource out) throws IOException {
483                InputStream is=null;
484                OutputStream os=null;
485                try {
486                        is=toBufferedInputStream(in.getInputStream());
487                        os=toBufferedOutputStream(out.getOutputStream());
488                }
489                catch(IOException ioe) {
490                        closeEL(os);
491                        closeEL(is);
492                        throw ioe;
493                }
494                copy(is,os);
495        }
496    
497    public static String toVariableName(String str, boolean addIdentityNumber) {
498                StringBuffer rtn=new StringBuffer();
499                char[] chars=str.toCharArray();
500                long changes=0;
501                for(int i=0;i<chars.length;i++) {
502                        char c=chars[i];
503                        if(i==0 && (c>='0' && c<='9'))rtn.append("_"+c);
504                        else if((c>='a' && c<='z') ||(c>='A' && c<='Z') ||(c>='0' && c<='9') || c=='_' || c=='$')
505                                rtn.append(c);
506                        else {  
507                            rtn.append('_');
508                                changes+=(c*(i+1));
509                        }
510                }
511                if(addIdentityNumber && changes>0)rtn.append(changes);
512                return rtn.toString();
513        }
514    
515    public static String first(String str,String delimiter){
516                StringTokenizer st=new StringTokenizer(str,delimiter);
517                return st.nextToken();
518        }
519        
520        public static String last(String str,String delimiter){
521                StringTokenizer st=new StringTokenizer(str,delimiter);
522                String rtn=null;
523                while(st.hasMoreTokens())
524                        rtn= st.nextToken();
525                return rtn;
526        }
527
528        public static String removeQuotes(String str, boolean trim) {
529                if(str==null) return str;
530                if(trim)str=str.trim();
531                if(str.length()<2) return str;
532                
533                char first=str.charAt(0);
534                char last=str.charAt(str.length()-1);
535                
536                if((first=='"' || first=='\'') && first==last)
537                        return str.substring(1,str.length()-1);
538                
539                return str;
540        }
541
542        public static void delete(File f) {
543                if(f.isDirectory()) {
544                        for(File c:f.listFiles()){
545                                delete(c);
546                        }
547                }
548                f.delete();
549        }
550}