fix of human readable size and media info
[mir.git] / source / mir / misc / StringUtil.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package  mir.misc;
31
32 import gnu.regexp.RE;
33 import gnu.regexp.REException;
34
35 import java.text.NumberFormat;
36 import java.util.Calendar;
37 import java.util.Date;
38 import java.util.GregorianCalendar;
39 import java.util.TimeZone;
40
41 /**
42  */
43 public final class StringUtil {
44
45   private static RE   re_newline2br, re_brbr2p, re_mail, re_url, re_tags,
46                       re_tables, re_forbiddenTags;
47
48   private StringUtil() { }  // this avoids contruction
49
50   static {
51     try {
52       //precompile regex
53       re_newline2br = new RE("(\r?\n){1}");
54       re_brbr2p     = new RE("(<br>\r?\n<br>){1,}");
55       re_mail       = new RE("\\b([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_.-]+)\\b");
56       re_url        = new RE("((https://)|(http://)|(ftp://)){1}([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>\\)\\]]+[^ \t\r\n.,<>\\)\\]])");
57       re_tags       = new RE("<[^>]*>",RE.REG_ICASE);
58       re_tables = new RE("<[ \t\r\n/]*(table|td|tr)[ \t\r\n]*>",RE.REG_ICASE);
59       re_forbiddenTags = new RE("<[ \t\r\n/]*(html|meta|body|head|script)[ \t\r\n]*>",RE.REG_ICASE);
60     }
61     catch (REException e){
62       System.err.println("FATAL: StringUtil: could not precompile REGEX: "+e.toString());
63     }
64   }
65
66   /**
67    * Formats a number with the specified minimum and maximum number of digits.
68    **/
69   public static synchronized String zeroPaddingNumber(long value, int minDigits,
70       int maxDigits)
71   {
72     NumberFormat numberFormat = NumberFormat.getInstance();
73     numberFormat.setMinimumIntegerDigits(minDigits);
74     numberFormat.setMaximumIntegerDigits(maxDigits);
75     return numberFormat.format(value);
76   }
77
78   /**
79    * Wandelt Datum in einen 8-ziffrigen String um (yyyymmdd)
80    * @param theDate
81    * @return 8-ziffriger String (yyyymmdd)
82    */
83
84   public static final String date2webdbDate (GregorianCalendar theDate) {
85     StringBuffer webdbDate = new StringBuffer();
86     webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
87     webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
88     webdbDate.append(pad2(theDate.get(Calendar.DATE)));
89
90     return  webdbDate.toString();
91   }
92
93   /**
94    * Wandelt Calendar in einen 12-ziffrigen String um (yyyymmddhhmm)
95    * @param theDate
96    * @return 12-ziffriger String (yyyymmdd)
97    */
98
99   public static final String date2webdbDateTime (GregorianCalendar theDate) {
100     StringBuffer webdbDate = new StringBuffer();
101     webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
102     webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
103     webdbDate.append(pad2(theDate.get(Calendar.DATE)));
104     webdbDate.append(pad2(theDate.get(Calendar.HOUR)));
105     webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
106
107     return  webdbDate.toString();
108   }
109
110   /**
111    * Return a http://www.w3.org/TR/NOTE-datetime formatted date (yyyy-mm-ddThh:mm:ssTZ)
112    * @param theDate
113    * @return w3approved datetime
114    */
115
116   public static final String date2w3DateTime (GregorianCalendar theDate) {
117     StringBuffer webdbDate = new StringBuffer();
118     webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
119     webdbDate.append("-");
120     webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
121     webdbDate.append("-");
122     webdbDate.append(pad2(theDate.get(Calendar.DATE)));
123     webdbDate.append("T");
124     webdbDate.append(pad2(theDate.get(Calendar.HOUR_OF_DAY)));
125     webdbDate.append(":");
126     webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
127     webdbDate.append(":");
128     webdbDate.append(pad2(theDate.get(Calendar.SECOND)));
129     //assumes you are an hour-multiple away from UTC....
130     int offset=(theDate.get(Calendar.ZONE_OFFSET)/(60*60*1000));
131     if (offset < 0){
132       webdbDate.append("-");
133     }
134     else{
135       webdbDate.append("+");
136     }
137     webdbDate.append(pad2(Math.abs(offset)));
138     webdbDate.append(":00");
139     return  webdbDate.toString();
140   }
141
142   /**
143    * wandelt Calendar in dd.mm.yyyy / hh.mm um
144    * @param theDate
145    * @return String mit (dd.mm.yyyy / hh.mm um)
146    */
147   public static String date2readableDateTime (GregorianCalendar theDate) {
148     String readable = "";
149     int hour;
150     readable += pad2(theDate.get(Calendar.DATE));
151     readable += "." + pad2(theDate.get(Calendar.MONTH) + 1);
152     readable += "." + String.valueOf(theDate.get(Calendar.YEAR));
153     hour = theDate.get(Calendar.HOUR);
154     if (theDate.get(Calendar.AM_PM) == Calendar.PM)
155       hour += 12;
156     readable += " / " + pad2(hour);
157     readable += ":" + pad2(theDate.get(Calendar.MINUTE));
158     return  readable;
159   }
160
161   /**
162   *  deleteForbiddenTags
163   *  this method deletes all <script>, <body> and <head>-tags
164   */
165   public static final String deleteForbiddenTags(String haystack) {
166     return re_forbiddenTags.substituteAll(haystack,"");
167   }
168
169   /**
170    *  deleteHTMLTableTags
171    *  this method deletes all <table>, <tr> and <td>-tags
172    */
173   public static final String deleteHTMLTableTags(String haystack) {
174     return re_tables.substituteAll(haystack,"");
175   }
176
177   /**
178    * wandelt eine Datum in einen 8-buchstabigen String, der durch <code>/</code>
179    * getrennt ist.
180    *
181    * @param webdbDate
182    * @return String mit <code>/yyyy/mm/dd</code>
183    */
184   public static final String webdbDate2path (String webdbDate) {
185     StringBuffer path = new StringBuffer();
186     path.append("/").append(webdbDate.substring(0, 4));
187     path.append("/").append(webdbDate.substring(4, 6));
188     path.append("/");
189     //who did this?
190     //path.append("/").append(webdbDate.substring(6, 8));
191     return  path.toString();
192   }
193
194   /**
195    * Replaces in <code>haystack</code> matching <code>pattern</code> by <code>substitute</code>
196    * @param haystack
197    * @param pattern
198    * @param substitute
199    * @return String with replacements.
200    */
201   public static String regexpReplace(String haystack, String pattern, String substitute) {
202     try {
203       RE regex = new RE(pattern);
204       return regex.substituteAll(haystack,substitute);
205     } catch(REException ex){
206       return null;
207     }
208   }
209
210   /**
211    * L?scht <code>/</code> am Ende des Strings, falls vorhanden
212    * @param path
213    * @return String ohne <code>/</code> am Ende
214    */
215   public static final String removeSlash (String path) {
216     return  path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length()
217         - 1) : path;
218   }
219
220   /**
221    * formatiert eine Zahl (0-99) zweistellig (z.B. 5 -> 05)
222    * @return zwistellige Zahl
223    */
224   public static String pad2 (int number) {
225     return  number < 10 ? "0" + number : String.valueOf(number);
226   }
227
228   /**
229    * formatiert eine Zahl (0-999) dreistellig (z.B. 7 -> 007)
230    *
231    * @return 3-stellige Zahl
232    */
233   public static String pad3 (int number) {
234     return  number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number);
235   }
236
237   /**
238    * Liefert Default-Wert def zur?ck, wenn String <code>s</code>
239    * kein Integer ist.
240    *
241    * @param s
242    * @param def
243    * @return geparster int aus s oder def
244    */
245   public static int parseInt(String s, int def) {
246     if (s == null) return def;
247     try {
248       return Integer.parseInt(s);
249     } catch (NumberFormatException e) {
250       return def;
251     }
252   }
253
254
255   /**
256    *  convertNewline2P ist eine regex-routine zum umwandeln von 2 oder mehr newlines (\n)
257    *  in den html-tag <p>
258    *  nur sinnvoll, wenn text nicht im html-format eingegeben
259    */
260   private static String convertNewline2P(String haystack) {
261     return re_brbr2p.substituteAll(haystack,"\n</p><p>");
262   }
263
264   /**
265    *  convertNewline2Break ist eine regex-routine zum umwandeln von 1 newline (\n)
266    *  in den html-tag <br>
267    *  nur sinnvoll, wenn text nicht im html-format eingegeben
268    */
269   private static String convertNewline2Break(String haystack) {
270     return re_newline2br.substituteAll(haystack,"$0<br />");
271   }
272
273   /**
274    *  createMailLinks wandelt text im email-adressenformat
275    *  in einen klickbaren link um
276    *  nur sinnvoll, wenn text nicht im html-format eingegeben
277    */
278   private static String createMailLinks(String haystack) {
279     return re_mail.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");
280   }
281
282
283   /**
284    *  createMailLinks wandelt text im email-adressenformat
285    *  in einen klickbaren link um
286    *  nur sinnvoll, wenn text nicht im html-format eingegeben
287    */
288   private static String createMailLinks(String haystack, String imageRoot, String mailImage) {
289     return re_mail.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");
290   }
291
292
293   /**
294    *  createURLLinks wandelt text im url-format
295    *  in einen klickbaren link um
296    *  nur sinnvoll, wenn text nicht im html-format eingegeben
297    */
298   private static String createURLLinks(String haystack) {
299     return re_url.substituteAll(haystack,"<a href=\"$0\">$0</a>");
300   }
301
302   /**
303    * this routine takes text in url format and makes
304    * a clickaeble "<href>" link removing any "illegal" html tags
305    * @param haystack  the url
306    * @param title  the href link text
307    * @param imageRoot  the place to find icons
308    * @param extImage  the url of the icon to show next to the link
309    * @return a String containing the url
310    */
311   private static String createURLLinks(String haystack, String title, String imageRoot,String extImage) {
312     if (title == null) {
313       return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");
314     }
315                 title = removeHTMLTags(title);
316                 return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">"+title+"</a>");
317   }
318
319   /**
320    * this routine takes text in url format and makes
321    * a clickaeble "<href>" link removing any "illegal" html tags
322    * @param haystack the url
323    * @param imageRoot the place to find icons
324    * @param extImage the url of the icon to show next to the link
325    * @param intImage unused
326    * @return a String containing the url
327    */
328   private static String createURLLinks(String haystack, String title, String imageRoot,String extImage,String intImage) {
329     return createURLLinks(haystack, title, imageRoot, extImage);
330   }
331
332   /**
333    * this method deletes all html tags
334    */
335   public static String removeHTMLTags(String haystack){
336     return re_tags.substituteAll(haystack,"");
337   }
338
339
340   /**
341    *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
342    *  htmlcodierten string auf und returnt einen htmlcodierten String
343    */
344   public static String createHTML(String content){
345     content=convertNewline2Break(content);
346     content=convertNewline2P(content);
347     content=createMailLinks(content);
348     content=createURLLinks(content);
349     return content;
350   }
351
352
353   /**
354    *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
355    *  htmlcodierten string auf und returnt einen htmlcodierten String
356    */
357   public static String createHTML(String content,String producerDocRoot,String mailImage,String extImage,String intImage){
358     content=convertNewline2Break(content);
359     content=convertNewline2P(content);
360     content=createMailLinks(content, producerDocRoot,mailImage);
361     content=createURLLinks(content, null, producerDocRoot, extImage, intImage);
362
363     return content;
364   }
365
366   /**
367    * Converts mir's horrible internal date format (yyyy-MM-dd HH:mm:ss+zz) into a java Date
368    *
369    * @param anInternalDate
370    */
371   public static Date convertMirInternalDateToDate(String anInternalDate) {
372     Calendar calendar = new GregorianCalendar();
373
374     int year;
375     int month;
376     int day;
377     int hours;
378     int minutes;
379     int seconds;
380     int timezoneOffset;
381
382     year = Integer.parseInt(anInternalDate.substring(0,4));
383     month = Integer.parseInt(anInternalDate.substring(5,7));
384     day = Integer.parseInt(anInternalDate.substring(8,10));
385     hours = Integer.parseInt(anInternalDate.substring(11,13));
386     minutes = Integer.parseInt(anInternalDate.substring(14,16));
387     seconds = Integer.parseInt(anInternalDate.substring(17,19));
388
389     timezoneOffset = Integer.parseInt(anInternalDate.substring(20,22));
390     if (anInternalDate.charAt(19) == '-')
391       timezoneOffset = -timezoneOffset;
392
393     calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
394     calendar.set(year, month-1, day, hours, minutes, seconds);
395     calendar.add(Calendar.HOUR, -timezoneOffset);
396
397     return calendar.getTime();
398   }
399
400 }
401