re-introduce leaner/simpler encodeHTML(String aText) method, we need it for the admin...
[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 the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package  mir.misc;
33
34 import  java.io.*;
35 import  java.lang.*;
36 import  java.util.*;
37 import  java.text.NumberFormat;
38 import  gnu.regexp.*;
39
40 /**
41  * Statische Hilfsmethoden zur Stringbehandlung
42  *
43  * @version $Id: StringUtil.java,v 1.23.2.4 2002/12/10 09:07:50 mh Exp $
44  * @author rk, mir-coders group
45  *
46  */
47
48 public final class StringUtil {
49
50         private static RE   re_newline2br, re_brbr2p, re_mail, re_url, re_tags;
51
52         private StringUtil() { }  // this avoids contruction
53
54         static {
55                 try {
56                         //precompile regex
57                         re_newline2br = new RE("(\r?\n){1}");
58                         re_brbr2p     = new RE("(<br>\r?\n<br>){1,}");
59       re_mail       = new RE("([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_.-]+)");
60                         re_url        = new RE("((https://)|(http://)|(ftp://)){1}([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>\\)\\]]+[^ \t\r\n.,<>\\)\\]])");
61                         re_tags       = new RE("<[^>]*>",RE.REG_ICASE);
62                 }
63                 catch (REException e){
64                         System.err.println("FATAL: StringUtil: could not precompile REGEX: "+e.toString());
65                 }
66         }
67
68   /**
69    * Formats a number with the specified minimum and maximum number of digits.
70    **/
71   public static synchronized String zeroPaddingNumber(long value, int minDigits,
72                                                       int maxDigits)
73   {
74     NumberFormat numberFormat = NumberFormat.getInstance();
75     numberFormat.setMinimumIntegerDigits(minDigits);
76     numberFormat.setMaximumIntegerDigits(maxDigits);
77     return numberFormat.format(value);
78   }
79
80         /**
81          * Wandelt Datum in einen 8-ziffrigen String um (yyyymmdd)
82          * @param theDate
83          * @return 8-ziffriger String (yyyymmdd)
84          */
85
86         public static final String date2webdbDate (GregorianCalendar theDate) {
87                 StringBuffer webdbDate = new StringBuffer();
88                 webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
89                 webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
90                 webdbDate.append(pad2(theDate.get(Calendar.DATE)));
91                 return  webdbDate.toString();
92         }
93
94         /**
95          * Wandelt Calendar in einen 12-ziffrigen String um (yyyymmddhhmm)
96          * @param theDate
97          * @return 12-ziffriger String (yyyymmdd)
98          */
99
100         public static final String date2webdbDateTime (GregorianCalendar theDate) {
101                 StringBuffer webdbDate = new StringBuffer();
102                 webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
103                 webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
104                 webdbDate.append(pad2(theDate.get(Calendar.DATE)));
105                 webdbDate.append(pad2(theDate.get(Calendar.HOUR)));
106                 webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
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)));
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          * wandelt eine Datum in einen 8-buchstabigen String, der durch <code>/</code>
163          * getrennt ist.
164          *
165          * @param webdbDate
166          * @return String mit <code>/yyyy/mm/dd</code>
167          */
168         public static final String webdbDate2path (String webdbDate) {
169                 StringBuffer path = new StringBuffer();
170                 path.append("/").append(webdbDate.substring(0, 4));
171                 path.append("/").append(webdbDate.substring(4, 6));
172                 path.append("/");
173                 //who did this?
174                 //path.append("/").append(webdbDate.substring(6, 8));
175                 return  path.toString();
176         }
177
178         /**
179          * wandelt Calendar in dd.mm.yyyy um
180          *
181          * @param theDate
182          * @return String mit  <code>yyyy.mm.dd</code>
183          */
184         public static final String webdbDate2readableDate (String webdbDate) {
185                 String date = "";
186                 date += webdbDate.substring(0, 4);
187                 date += "-" + webdbDate.substring(5, 7);
188                 date += "-"+webdbDate.substring(8, 10);
189                 return  date;
190         }
191
192
193         /**
194          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
195          * to dd.mm.yyyy hh:mm
196          */
197         public static String dateToReadableDate(String date) {
198                 StringBuffer returnDate = new StringBuffer();
199                 if (date!=null) {
200
201                         returnDate.append(date.substring(8,10)).append('.');
202                         returnDate.append(date.substring(5,7)).append('.');
203                         returnDate.append(date.substring(0,4)).append(' ');
204                         returnDate.append(date.substring(11,16));
205                 }
206                 return returnDate.toString();
207         }
208         
209   /**
210          * converts string from format: yyyy-mm-dd__hh:mm:ss.dddddd+TZ
211          * to yyyy-mm-ddThh:mm:ss+TZ:00 (w3 format for Dublin Core)
212          */
213         public static String webdbdateToDCDate(String date) {
214                 StringBuffer returnDate = new StringBuffer();
215                 if (date!=null) {
216       returnDate.append(date.substring(0,10));
217       returnDate.append("T");
218       returnDate.append(date.substring(11,19));
219       //String tzInfo=date.substring(26,29);
220       //if (tzInfo.equals("+00")){
221       //UTC gets a special code in w3 dates
222       //    returnDate.append("Z");
223       //}
224       //else{
225       //need to see what a newfoundland postgres
226       //timestamp looks like before making this robust
227       //    returnDate.append(tzInfo);
228       //    returnDate.append(":00");
229       //}
230
231                 }
232                 return returnDate.toString();
233         }
234
235
236         /**
237          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
238          * to yyyy
239          */
240         public static String dateToYear (String date) {
241                 StringBuffer returnDate = new StringBuffer();
242                 if (date!=null) {
243
244                         returnDate.append(date.substring(0,4));
245                 }
246                 return returnDate.toString();
247         }
248
249         /**
250          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
251          * to [m]m
252          */
253         public static String dateToMonth (String date) {
254                 StringBuffer returnDate = new StringBuffer();
255                 if (date!=null) {
256                         if (!date.substring(5,6).equalsIgnoreCase("0")) returnDate.append(date.substring(5,7));
257                         else returnDate.append(date.substring(6,7));
258                 }
259                 return returnDate.toString();
260         }
261
262         /**
263          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
264          * to [d]d
265          */
266         public static String dateToDayOfMonth (String date) {
267                 StringBuffer returnDate = new StringBuffer();
268                 if (date!=null) {
269                         if (!date.substring(8,9).equalsIgnoreCase("0")) returnDate.append(date.substring(8,10));
270                         else returnDate.append(date.substring(9,10));
271                 }
272                 return returnDate.toString();
273         }
274
275         /**
276          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
277          * to hh:mm
278          */
279         public static String dateToTime (String date) {
280                 StringBuffer returnDate = new StringBuffer();
281                 if (date!=null) {
282                         returnDate.append(date.substring(11,16));
283                 }
284                 return returnDate.toString();
285         }
286
287     /**
288      * Splits the provided CSV text into a list. stolen wholesale from
289      * from Jakarta Turbine StrinUtils.java -mh
290      *
291      * @param text      The CSV list of values to split apart.
292      * @param separator The separator character.
293      * @return          The list of values.
294      */
295     public static String[] split(String text, String separator)
296     {
297         StringTokenizer st = new StringTokenizer(text, separator);
298         String[] values = new String[st.countTokens()];
299         int pos = 0;
300         while (st.hasMoreTokens())
301         {
302             values[pos++] = st.nextToken();
303         }
304         return values;
305     }
306
307     /**
308      * Joins the elements of the provided array into a single string
309      * containing a list of CSV elements. Stolen wholesale from Jakarta
310      * Turbine StringUtils.java. -mh
311      *
312      * @param list      The list of values to join together.
313      * @param separator The separator character.
314      * @return          The CSV text.
315      */
316     public static String join(String[] list, String separator)
317     {
318         StringBuffer csv = new StringBuffer();
319         for (int i = 0; i < list.length; i++)
320         {
321             if (i > 0)
322             {
323                 csv.append(separator);
324             }
325             csv.append(list[i]);
326         }
327         return csv.toString();
328     }
329
330
331         /**
332          * schließt einen String in Anführungsszeichen ein, falls er Leerzeichen o.ä. enthält
333          *
334          * @return gequoteter String
335          */
336          public static String quoteIfNecessary(String s) {
337                 for (int i = 0; i < s.length(); i++)
338                         if (!(Character.isLetterOrDigit(s.charAt(i)) || s.charAt(i) == '.'))
339                                 return quote(s, '"');
340                 return s;
341         }
342
343          /**
344          * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
345          * "gefährliche" Zeichen innerhalb des Strings
346          * Quotes special SQL-characters in <code>s</code>
347          *
348          * @return geqoteter String
349          */
350         public static String quote(String s)
351         {
352                 //String s2 = quote(s, '\'');
353                 //Quickhack     ÃŠÃŠ ÃŠ ÃŠ ÃŠ ÃŠ ÃŠ ÃŠ
354                 //Because of '?-Bug in Postgresql-JDBC-Driver
355                 StringBuffer temp = new StringBuffer();
356                 for(int i=0;i<s.length();i++){
357                         if(s.charAt(i)=='\''){
358                                 temp.append("&#39;");
359                         } else {
360                                 temp.append(s.charAt(i));
361                         }
362                 }
363                 String s2 = temp.toString();
364                 //end Quickhack
365                 
366                 s2 = quote(s2, '\"');
367                 return s2;
368         }
369
370         /**
371          * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
372          * "gefährliche" Zeichen innerhalb des Strings
373          *
374          * @param s String, der gequoted werden soll
375          * @param quoteChar zu quotendes Zeichen
376          * @return gequoteter String
377          */
378         public static String quote(String s, char quoteChar)
379         {
380                 StringBuffer buf = new StringBuffer(s.length());
381                 int pos = 0;
382                 while (pos < s.length()) {
383                         int i = s.indexOf(quoteChar, pos);
384                         if (i < 0) i = s.length();
385                         buf.append(s.substring(pos, i));
386                         pos = i;
387                         if (pos < s.length()) {
388                                 buf.append('\\');
389                                 buf.append(quoteChar);
390                                 pos++;
391                         }
392                 }
393                 return buf.toString();
394         }
395
396         /**
397          * replaces dangerous characters in <code>s</code>
398          *
399          */
400
401         public static String unquote(String s)
402         {
403                 char quoteChar='\'';
404                 StringBuffer buf = new StringBuffer(s.length());
405                 int pos = 0;
406                 String searchString = "\\"+quoteChar;
407                 while (pos < s.length()) {
408                         int i = s.indexOf(searchString, pos);
409                         if (i < 0) i = s.length();
410                         buf.append(s.substring(pos, i));
411                         pos = i+1;
412                 }
413                 return buf.toString();
414         }
415
416   /*
417    * replaces characters that cannot appera in HTML with escaped equivalents.
418    */
419   public static String encodeHTML(String aText) {
420     final char[] CHARACTERS_TO_ESCAPE = { '&', '<', '>', '"', '\'' };
421     final String[] ESCAPE_CODES = { "&amp;", "&lt;", "&gt;", "&quot;", "&apos;" };
422
423     int position, nextPosition;
424     int i;
425     StringBuffer result = new StringBuffer();
426
427     position=0;
428
429     do {
430       nextPosition = indexOfCharacters(aText, CHARACTERS_TO_ESCAPE, position);
431
432       if (nextPosition<0)
433         nextPosition = aText.length();
434
435       result.append(aText.substring(position, nextPosition));
436
437       if (nextPosition<aText.length())
438         for (i=0; i<CHARACTERS_TO_ESCAPE.length; i++) {
439           if (CHARACTERS_TO_ESCAPE[i] == aText.charAt(nextPosition)) {
440             result.append(ESCAPE_CODES[i]);
441             break;
442           }
443         }
444       position=nextPosition+1;
445     }
446     while (nextPosition<aText.length()) ;
447
448     return result.toString();
449   }
450
451         /**
452          * Wandelet String in byte[] um.
453          * @param s
454          * @return byte[] des String
455          */
456
457         public static byte[] stringToBytes(String s) {
458                 String crlf = System.getProperty("line.separator");
459                 if (!crlf.equals("\n"))
460                         s = replace(s, "\n", crlf);
461                 // byte[] buf = new byte[s.length()];
462                 byte[] buf = s.getBytes();
463                 return buf;
464         }
465
466                 /**
467          * Ersetzt in String <code>s</code> das <code>pattern</code> durch <code>substitute</code>
468          * @param s
469          * @param pattern
470          * @param substitute
471          * @return String mit den Ersetzungen
472          */
473         public static String replace(String s, String pattern, String substitute) {
474                 int i = 0, pLen = pattern.length(), sLen = substitute.length();
475                 StringBuffer buf = new StringBuffer(s.length());
476                 while (true) {
477                         int j = s.indexOf(pattern, i);
478                         if (j < 0) {
479                                 buf.append(s.substring(i));
480                                 break;
481                         } else {
482                                 buf.append(s.substring(i, j));
483                                 buf.append(substitute);
484                                 i = j+pLen;
485                         }
486                 }
487                 return buf.toString();
488         }
489
490         /**
491          * Ersetzt in String <code>s</code> das Regexp <code>pattern</code> durch <code>substitute</code>
492          * @param s
493          * @param pattern
494          * @param substitute
495          * @return String mit den Ersetzungen
496          */
497         public static String regexpReplace(String haystack, String pattern, String substitute) {
498                 try {
499                         RE regex = new RE(pattern);
500                         return regex.substituteAll(haystack,substitute);
501                 } catch(REException ex){
502                         return null;
503                 }
504         }
505
506
507
508
509         /**
510          * Fügt einen Separator an den Pfad an
511          * @param path
512          * @return Pfad mit Separator am Ende
513          */
514         public static final String addSeparator (String path) {
515                 return  path.length() == 0 || path.endsWith(File.separator) ? path : path
516                                 + File.separatorChar;
517         }
518
519         /**
520          * Fügt ein <code>/</code> ans ende des Strings and
521          * @param path
522          * @return Pfad mit <code>/</code> am Ende
523          */
524         public static final String addSlash (String path) {
525                 return  path.length() == 0 || path.endsWith("/") ? path : path + '/';
526         }
527
528         /**
529          * Löscht <code>/</code> am Ende des Strings, falls vorhanden
530          * @param path
531          * @return String ohne <code>/</code> am Ende
532          */
533         public static final String removeSlash (String path) {
534                 return  path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length()
535                                 - 1) : path;
536         }
537
538         /**
539          * Checks to see if the path is absolute by looking for a leading file
540          * separater
541          * @param path
542          * @return
543          */
544         public static boolean isAbsolutePath (String path) {
545                 return  path.startsWith(File.separator);
546         }
547
548         /**
549          * Löscht Slash am Anfang des Strings
550          * @param path
551          * @return
552          */
553         public static String removeFirstSlash (String path) {
554                 return  path.startsWith("/") ? path.substring(1) : path;
555         }
556
557         /**
558          * formatiert eine Zahl (0-99) zweistellig (z.B. 5 -> 05)
559          * @return zwistellige Zahl
560          */
561         public static String pad2 (int number) {
562                 return  number < 10 ? "0" + number : String.valueOf(number);
563         }
564
565         /**
566          * formatiert eine Zahl (0-999) dreistellig (z.B. 7 -> 007)
567          *
568          * @return 3-stellige Zahl
569          */
570         public static String pad3 (int number) {
571                 return  number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number);
572         }
573
574         /**
575          * Konvertiert Unix-Linefeeds in Win-Linefeeds
576          * @param s
577          * @return Konvertierter String
578          */
579         public static String unixLineFeedsToWin(String s) {
580                 int i = -1;
581                 while (true) {
582                         i = s.indexOf('\n', i+1);
583                         if (i < 0) break;
584                         if ((i == 0 || s.charAt(i-1) != '\r') &&
585                                 (i == s.length()-1 || s.charAt(i+1) != '\r')) {
586                                 s = s.substring(0, i)+'\r'+s.substring(i);
587                                 i++;
588                         }
589                 }
590                 return s;
591         }
592
593
594         /**
595          * verwandelt einen String in eine gültige Url, konvertiert Sonderzeichen
596          * und Spaces werden zu Underscores
597          *
598          * @return gültige Url
599          */
600         public static String convert2url(String s) {
601                 s = toLowerCase(s);
602                 StringBuffer buf = new StringBuffer();
603                 for(int i = 0; i < s.length(); i++ ) {
604                                 switch( s.charAt( i ) ) {
605                                 case 'ö':
606                         buf.append( "oe" ); break;
607                                 case 'ä':
608                         buf.append( "ae" ); break;
609                                 case 'ü':
610                         buf.append( "ue" ); break;
611                                 case 'ã':
612                         buf.append( "a" ); break;
613                                 case '´':
614                                 case '.':
615                         buf.append( "_" ); break;
616                                 case ' ':
617                         if( buf.charAt( buf.length() - 1 ) != '_' ) {
618                                         buf.append( "_" );
619                         }
620                         break;
621                                 default:
622                         buf.append( s.charAt( i ) );
623                                 }
624                 }
625                 return buf.toString();
626         }
627
628         public static String replaceQuot(String s) {
629                 StringBuffer buffer = new StringBuffer();
630                 for(int j = 0; j < s.length();j++){
631                         if(s.charAt(j)=='&'){
632                                 if(s.indexOf( "&quot;",j) == j) {
633                                         buffer.append( "\"" );
634                                         j += 5;
635                                 }//if
636                         } else {
637                                 buffer.append(s.charAt(j));
638                         }//else
639                 }//for
640                 return buffer.toString();
641         }
642
643         /**
644          * schnellere Variante der String.toLowerCase()-Routine
645          *
646          * @return String in Kleinbuchsten
647          */
648         public static String toLowerCase(String s) {
649                 int l = s.length();
650                 char[] a = new char[l];
651                 for (int i = 0; i < l; i++)
652                         a[i] = Character.toLowerCase(s.charAt(i));
653                 return new String(a);
654         }
655
656          /**
657          * Finds <code>element</code> in String-Array <code>array</code>
658          * @param array
659          * @param element
660          * @return Position where the element was found or -1
661          */
662         public static int indexOf(String[] array, String element) {
663                 if (array != null)
664                         for (int i = 0; i < array.length; i++)
665                                 if (array[i].equals(element))
666                                         return i;
667                 return -1;
668         }
669
670          /**
671    * Finds position of first in <code>aCharacters</code> array in String
672    * <code>aString</code> starting from position <code>aFrom</code>
673    *
674          * @param aString
675          * @param aCharacters
676    * @param aFrom
677          * @return Position where the element was found or -1
678          */
679   public static int indexOfCharacters(String aString, char[] aCharacters, int aFrom) {
680     int i;
681     int result=-1;
682     int position;
683
684     for (i=0; i<aCharacters.length ; i++) {
685       position = aString.indexOf(aCharacters[i], aFrom);
686
687       if (position != -1 && ( result == -1 || position < result )) {
688         result = position;
689       }
690     }
691
692     return result;
693   }
694
695
696         /**
697          * Testet auf Vorkommen von <code>element</code> in <code>array</code>
698          * @param array String-Array
699          * @param element
700          * @return true wenn <code>element</code> vorkommt, sonst false
701          */
702         public static boolean contains(String[] array, String element) {
703                 return indexOf(array, element) >= 0;
704         }
705
706                 /**
707          * Ermittelt CRC-Prüfsumme von String <code>s</code>
708          * @param s
709          * @return CRC-Prüfsumme
710          */
711         public static int getCRC(String s) {
712                 int h = 0;
713                 char val[] = s.toCharArray();
714                 int len = val.length;
715
716                 for (int i = 0 ; i < len; i++) {
717                         h &= 0x7fffffff;
718                         h = (((h >> 30) | (h << 1)) ^ (val[i]+i));
719                 }
720
721                 return (h << 8) | (len & 0xff);
722         }
723
724                 /**
725          * Liefert Default-Wert def zurück, wenn String <code>s</code>
726          * kein Integer ist.
727          *
728          * @param s
729          * @param def
730          * @return geparster int aus s oder def
731          */
732         public static int parseInt(String s, int def) {
733                 if (s == null) return def;
734                 try {
735                         return Integer.parseInt(s);
736                 } catch (NumberFormatException e) {
737                         return def;
738                 }
739         }
740
741   public static String interpretAsString(Object aValue) throws Exception {
742     if (aValue instanceof String)
743       return (String) aValue;
744
745     if (aValue instanceof Integer)
746       return ((Integer) aValue).toString();
747
748     if (aValue == null)
749       return "";
750
751     throw new Exception("String expected, "+aValue+" found");
752   }
753
754
755
756         /**
757          * Liefert Defaultwert def zurück, wenn s nicht zu einem float geparsed werden kann.
758          * @param s
759          * @param def
760          * @return geparster float oder def
761          */
762         public static float parseFloat(String s, float def) {
763                 if (s == null) return def;
764                 try {
765                         return new Float(s).floatValue();
766                 } catch (NumberFormatException e) {
767                         return def;
768                 }
769         }
770
771                 /**
772          * Findet Ende eines Satzes in String <code>text</code>
773          * @param text
774          * @param startIndex
775          * @return index des Satzendes, oder -1
776          */
777         public static int findEndOfSentence(String text, int startIndex) {
778                  while (true) {
779                          int i = text.indexOf('.', startIndex);
780                          if (i < 0) return -1;
781                          if (i > 0 && !Character.isDigit(text.charAt(i-1)) &&
782                                         (i+1 >= text.length()
783                                         || text.charAt(i+1) == ' '
784                                         || text.charAt(i+1) == '\n'
785                                         || text.charAt(i+1) == '\t'))
786                                         return i+1;
787                          startIndex = i+1;
788                  }
789         }
790
791                 /**
792          * Findet Wortende in String <code>text</code> ab <code>startIndex</code>
793          * @param text
794          * @param startIndex
795          * @return Index des Wortendes, oder -1
796          */
797         public static int findEndOfWord(String text, int startIndex) {
798                 int i = text.indexOf(' ', startIndex),
799                         j = text.indexOf('\n', startIndex);
800                 if (i < 0) i = text.length();
801                 if (j < 0) j = text.length();
802                 return Math.min(i, j);
803         }
804
805
806         /**
807          *  convertNewline2P ist eine regex-routine zum umwandeln von 2 oder mehr newlines (\n)
808          *  in den html-tag <p>
809          *  nur sinnvoll, wenn text nicht im html-format eingegeben
810          */
811         public static String convertNewline2P(String haystack) {
812                         return re_brbr2p.substituteAll(haystack,"\n</p><p>");
813         }
814
815         /**
816          *  convertNewline2Break ist eine regex-routine zum umwandeln von 1 newline (\n)
817          *  in den html-tag <br>
818          *  nur sinnvoll, wenn text nicht im html-format eingegeben
819          */
820         public static String convertNewline2Break(String haystack) {
821                 return re_newline2br.substituteAll(haystack,"$0<br />");
822         }
823
824         /**
825          *  createMailLinks wandelt text im email-adressenformat
826          *  in einen klickbaren link um
827          *  nur sinnvoll, wenn text nicht im html-format eingegeben
828          */
829         public static String createMailLinks(String haystack) {
830                         return re_mail.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");
831         }
832
833
834         /**
835          *  createMailLinks wandelt text im email-adressenformat
836          *  in einen klickbaren link um
837          *  nur sinnvoll, wenn text nicht im html-format eingegeben
838          */
839         public static String createMailLinks(String haystack, String imageRoot, String mailImage) {
840                 return re_mail.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");
841         }
842
843
844         /**
845          *  createURLLinks wandelt text im url-format
846          *  in einen klickbaren link um
847          *  nur sinnvoll, wenn text nicht im html-format eingegeben
848          */
849         public static String createURLLinks(String haystack) {
850                 return re_url.substituteAll(haystack,"<a href=\"$0\">$0</a>");
851         }
852
853         /**
854          * this routine takes text in url format and makes
855          * a clickaeble "<href>" link removing any "illegal" html tags
856          * @param haystack, the url
857          * @param title, the href link text
858          * @param imagRoot, the place to find icons
859          * @param extImage, the url of the icon to show next to the link
860          * @return a String containing the url
861          */
862         public static String createURLLinks(String haystack, String title, String imageRoot,String extImage) {
863                 if (title == null) {
864                         return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");
865                 } else {
866                         title = removeHTMLTags(title);
867                         return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">"+title+"</a>");
868                 }
869         }
870
871         /**
872          * this routine takes text in url format and makes
873          * a clickaeble "<href>" link removing any "illegal" html tags
874          * @param haystack, the url
875          * @param imageRoot, the place to find icons
876          * @param extImage, the url of the icon to show next to the link
877          * @param intImage, unused
878          * @return a String containing the url
879          */
880         public static String createURLLinks(String haystack, String title, String imageRoot,String extImage,String intImage) {
881                 return createURLLinks(haystack, title, imageRoot, extImage);
882         }
883
884          /**
885          *  deleteForbiddenTags
886          *  this method deletes all <script>, <body> and <head>-tags
887          */
888         public static final String deleteForbiddenTags(String haystack) {
889                 try {
890                         RE regex = new RE("<[ \t\r\n](.*?)script(.*?)/script(.*?)>",RE.REG_ICASE);
891                         haystack = regex.substituteAll(haystack,"");
892                         regex = new RE("<head>(.*?)</head>");
893                         haystack = regex.substituteAll(haystack,"");
894                         regex = new RE("<[ \t\r\n/]*body(.*?)>");
895                         haystack = regex.substituteAll(haystack,"");
896                         return haystack;
897                 } catch(REException ex){
898                         return null;
899                 }
900         }
901
902          /**
903          *  deleteHTMLTableTags
904          *  this method deletes all <table>, <tr> and <td>-tags
905          */
906         public static final String deleteHTMLTableTags(String haystack) {
907                 try {
908                         RE regex = new RE("</?(table|td|tr)>",RE.REG_ICASE);
909                         haystack = regex.substituteAll(haystack,"");
910                         return haystack;
911                 } catch(REException ex){
912                         return null;
913                 }
914         }
915
916         /**
917          * this method deletes all html tags
918          */
919         public static final String removeHTMLTags(String haystack){
920                         return re_tags.substituteAll(haystack,"");
921         }
922
923
924         /**
925          * this method deletes all but the approved tags html tags
926          * it also deletes approved tags which contain malicious-looking attributes and doesn't work at all
927          */
928         public static String approveHTMLTags(String haystack){
929                 try {
930                         String approvedTags="a|img|h1|h2|h3|h4|h5|h6|br|b|i|strong|p";
931                         String badAttributes="onAbort|onBlur|onChange|onClick|onDblClick|onDragDrop|onError|onFocus|onKeyDown|onKeyPress|onKeyUp|onLoad|onMouseDown|onMouseMove|onMouseOut|onMouseOver|onMouseUp|onMove|onReset|onResize|onSelect|onSubmit|onUnload";
932                         String approvedProtocols="rtsp|http|ftp|https|freenet|mailto";
933
934                         // kill all the bad tags that have attributes
935                         String s = "<\\s*/?\\s*(?!(("+approvedTags+")\\s))\\w+\\s[^>]*>";
936                         RE regex = new RE(s,RE.REG_ICASE);
937                         haystack = regex.substituteAll(haystack,"");
938
939                         // kill all the bad tags that are attributeless
940                         regex = new RE("<\\s*/?\\s*(?!(("+approvedTags+")\\s*>))\\w+\\s*>",RE.REG_ICASE);
941                         haystack = regex.substituteAll(haystack,"");
942
943                         // kill all the tags which have a javascript attribute like onLoad
944                         regex = new RE("<[^>]*("+badAttributes+")[^>]*>",RE.REG_ICASE);
945                         haystack = regex.substituteAll(haystack,"");
946
947                         // kill all the tags which include a url to an unacceptable protocol
948                         regex = new RE("<\\s*a\\s+[^>]*href=(?!(\'|\")?("+approvedProtocols+"))[^>]*>",RE.REG_ICASE);
949                         haystack = regex.substituteAll(haystack,"");
950
951                         return haystack;
952                 } catch(REException ex){
953                         ex.printStackTrace();
954                         return null;
955                 }
956         }
957
958
959         /**
960          *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
961          *  htmlcodierten string auf und returnt einen htmlcodierten String
962          */
963         public static String createHTML(String content){
964                 content=convertNewline2Break(content);
965                 content=convertNewline2P(content);
966                 content=createMailLinks(content);
967                 content=createURLLinks(content);
968                 return content;
969         }
970
971
972         /**
973          *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
974          *  htmlcodierten string auf und returnt einen htmlcodierten String
975          */
976         public static String createHTML(String content,String producerDocRoot,String mailImage,String extImage,String intImage){
977                 content=convertNewline2Break(content);
978                 content=convertNewline2P(content);
979                 content=createMailLinks(content,producerDocRoot,mailImage);
980                 content=createURLLinks(content,null,producerDocRoot,extImage,intImage);
981                 return content;
982         }
983
984 }
985