EMMA Coverage Report (generated Tue Mar 14 21:50:42 EST 2006)
[all classes][org.farng.mp3]

COVERAGE SUMMARY FOR SOURCE FILE [TagUtility.java]

nameclass, %method, %block, %line, %
TagUtility.java100% (1/1)73%  (22/30)80%  (1194/1484)80%  (286/357)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TagUtility100% (1/1)73%  (22/30)80%  (1194/1484)80%  (286/357)
TagUtility (): void 0%   (0/1)0%   (0/3)0%   (0/2)
addTimeStampToTextArea (String, int): String 0%   (0/1)0%   (0/66)0%   (0/16)
convertFrameID2_2to2_3 (String): String 0%   (0/1)0%   (0/21)0%   (0/5)
convertFrameID2_2to2_4 (String): String 0%   (0/1)0%   (0/30)0%   (0/8)
convertFrameID2_3to2_2 (String): String 0%   (0/1)0%   (0/21)0%   (0/5)
convertFrameID2_3to2_4 (String): String 0%   (0/1)0%   (0/21)0%   (0/5)
convertFrameID2_4to2_2 (String): String 0%   (0/1)0%   (0/30)0%   (0/8)
convertFrameID2_4to2_3 (String): String 0%   (0/1)0%   (0/18)0%   (0/5)
copyObject (Object): Object 100% (1/1)50%  (26/52)44%  (7/16)
getWholeNumber (Object): long 100% (1/1)79%  (52/66)93%  (13/14)
capitalizeWord (String, boolean): StringBuffer 100% (1/1)79%  (64/81)80%  (13.5/17)
findNumber (String, int): long 100% (1/1)88%  (91/103)94%  (17/18)
copyFile (File, File): void 100% (1/1)91%  (94/103)95%  (31.4/33)
findMatchingParenthesis (String, int): int 100% (1/1)98%  (99/101)96%  (23/24)
<static initializer> 100% (1/1)100% (25/25)100% (7/7)
appendBeforeExtension (String, String): String 100% (1/1)100% (39/39)100% (8/8)
findNumber (String): long 100% (1/1)100% (4/4)100% (1/1)
getFrameDescription (String): String 100% (1/1)100% (56/56)100% (14/14)
isID3v2_2FrameIdentifier (String): boolean 100% (1/1)100% (48/48)100% (10/10)
isID3v2_3FrameIdentifier (String): boolean 100% (1/1)100% (20/20)100% (5/5)
isID3v2_4FrameIdentifier (String): boolean 100% (1/1)100% (20/20)100% (5/5)
isLyrics3v2FieldIdentifier (String): boolean 100% (1/1)100% (20/20)100% (5/5)
isMatchingParenthesis (String): boolean 100% (1/1)100% (45/45)100% (13/13)
padString (String, int, char, boolean): String 100% (1/1)100% (82/82)100% (23/23)
replaceEOLNwithCRLF (String): String 100% (1/1)100% (51/51)100% (11/11)
replaceWord (String, String, String): String 100% (1/1)100% (93/93)100% (16/16)
stripChar (String, char): String 100% (1/1)100% (40/40)100% (8/8)
toSentenceCase (String, boolean): String 100% (1/1)100% (96/96)100% (23/23)
toTitleCase (String, boolean): String 100% (1/1)100% (103/103)100% (25/25)
truncate (String, int): String 100% (1/1)100% (26/26)100% (7/7)

1package org.farng.mp3;
2 
3import java.io.BufferedInputStream;
4import java.io.BufferedOutputStream;
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.FileNotFoundException;
8import java.io.FileOutputStream;
9import java.io.IOException;
10import java.lang.reflect.Constructor;
11import java.util.HashMap;
12import java.util.Iterator;
13import java.util.Map;
14import java.util.Stack;
15import java.util.StringTokenizer;
16 
17/**
18 * This is a holder class that contains static methods that I use in my library. They may or may not be useful for
19 * anyone else extending the library.
20 *
21 * @author Eric Farng
22 * @version $Revision: 1.4 $
23 */
24public class TagUtility {
25 
26    /**
27     * integer difference between ASCII 'A' and ASCII 'a'
28     */
29    private static final int UPPERCASE;
30    /**
31     * Convenience <code>HashMap</code> to help fix capitilization of words. It maps all words in
32     * <code>TagConstants.upperLowerCase</code> from all lower case to their desired capitilziation.
33     */
34    private static final Map capitalizationMap;
35 
36    static {
37        UPPERCASE = (int) 'A' - (int) 'a';
38        capitalizationMap = new HashMap(32);
39        final Iterator iterator = TagOptionSingleton.getInstance().getUpperLowerCaseWordListIterator();
40        while (iterator.hasNext()) {
41            final String word = (String) iterator.next();
42            capitalizationMap.put(word.toLowerCase(), word);
43        }
44    }
45 
46    /**
47     * Creates a new TagUtility object.
48     */
49    private TagUtility() {
50        super();
51    }
52 
53    /**
54     * Given an ID, get the ID3v2 frame description or the Lyrics3 field description. This takes any kind of ID (four or
55     * three letter ID3v2 IDs, and three letter Lyrics3 IDs)
56     *
57     * @param identifier frame identifier
58     *
59     * @return frame description
60     */
61    public static String getFrameDescription(final String identifier) {
62        if (identifier == null) {
63            throw new NullPointerException("Identifier is null");
64        }
65        String returnValue = null;
66        if (identifier.length() > 2) {
67            if (identifier.length() == 4) {
68                final String idPrefix = identifier.substring(0, 4);
69                returnValue = (String) TagConstant.id3v2_4FrameIdToString.get(idPrefix);
70                if (returnValue == null) {
71                    returnValue = (String) TagConstant.id3v2_3FrameIdToString.get(idPrefix);
72                }
73            }
74            if (returnValue == null) {
75                returnValue = (String) TagConstant.id3v2_2FrameIdToString.get(identifier.substring(0, 3));
76            }
77            if (returnValue == null) {
78                returnValue = (String) TagConstant.lyrics3v2FieldIdToString.get(identifier.substring(0, 3));
79            }
80        }
81        return returnValue;
82    }
83 
84    /**
85     * Returns true if the identifier is a valid ID3v2.2 frame identifier
86     *
87     * @param identifier string to test
88     *
89     * @return true if the identifier is a valid ID3v2.2 frame identifier
90     */
91    public static boolean isID3v2_2FrameIdentifier(final String identifier) {
92        if (identifier == null) {
93            throw new NullPointerException("Identifier is null");
94        }
95        if (identifier.length() < 3) {
96            return false;
97        } else if (identifier.length() == 3) {
98            return TagConstant.id3v2_2FrameIdToString.containsKey(identifier);
99        } else {
100            final String upperIdentifier = identifier.toUpperCase();
101            if (upperIdentifier.charAt(3) >= 'A' && upperIdentifier.charAt(3) <= 'Z') {
102                return TagConstant.id3v2_2FrameIdToString.containsKey(upperIdentifier.substring(0, 4));
103            }
104            return TagConstant.id3v2_2FrameIdToString.containsKey(upperIdentifier.subSequence(0, 3));
105        }
106    }
107 
108    /**
109     * Returns true if the identifier is a valid ID3v2.3 frame identifier
110     *
111     * @param identifier string to test
112     *
113     * @return true if the identifier is a valid ID3v2.3 frame identifier
114     */
115    public static boolean isID3v2_3FrameIdentifier(final String identifier) {
116        if (identifier == null) {
117            throw new NullPointerException("Identifier is null");
118        }
119        if (identifier.length() < 4) {
120            return false;
121        }
122        return TagConstant.id3v2_3FrameIdToString.containsKey(identifier.substring(0, 4));
123    }
124 
125    /**
126     * Returns true if the identifier is a valid ID3v2.4 frame identifier
127     *
128     * @param identifier string to test
129     *
130     * @return true if the identifier is a valid ID3v2.4 frame identifier
131     */
132    public static boolean isID3v2_4FrameIdentifier(final String identifier) {
133        if (identifier == null) {
134            throw new NullPointerException("Identifier is null");
135        }
136        if (identifier.length() < 4) {
137            return false;
138        }
139        return TagConstant.id3v2_4FrameIdToString.containsKey(identifier.substring(0, 4));
140    }
141 
142    /**
143     * Returns true if the identifier is a valid Lyrics3v2 frame identifier
144     *
145     * @param identifier string to test
146     *
147     * @return true if the identifier is a valid Lyrics3v2 frame identifier
148     */
149    public static boolean isLyrics3v2FieldIdentifier(final String identifier) {
150        if (identifier == null) {
151            throw new NullPointerException("Identifier is null");
152        }
153        if (identifier.length() < 3) {
154            return false;
155        }
156        return TagConstant.lyrics3v2FieldIdToString.containsKey(identifier.substring(0, 3));
157    }
158 
159    /**
160     * Returns true if the string has matching parenthesis. This method matches all four parenthesis and also enclosed
161     * parenthesis.
162     *
163     * @param str string to test
164     *
165     * @return true if the string has matching parenthesis
166     */
167    public static boolean isMatchingParenthesis(final String str) {
168        if (str == null) {
169            throw new NullPointerException("String is null");
170        }
171        final TagOptionSingleton option = TagOptionSingleton.getInstance();
172        final int length = str.length();
173        for (int i = 0; i < length; i++) {
174            final char ch = str.charAt(i);
175            if (option.isCloseParenthesis(Character.toString(ch))) {
176                return false;
177            }
178            if (option.isOpenParenthesis(Character.toString(ch))) {
179                i = findMatchingParenthesis(str, i);
180                if (i < 0) {
181                    return false;
182                }
183            }
184        }
185        return true;
186    }
187 
188    /**
189     * Given an object, try to return it as a <code>long</code>. This tries to parse a string, and takes <code>Long,
190     * Short, Byte, Integer</code> objects and gets their value. An exception is not explicityly thrown here because it
191     * would causes too many other methods to also throw it.
192     *
193     * @param value object to find long from.
194     *
195     * @return <code>long</code> value
196     */
197    public static long getWholeNumber(final Object value) {
198        if (value == null) {
199            throw new NullPointerException("Value is null");
200        }
201        final long number;
202        if (value instanceof String) {
203            number = Long.parseLong((String) value);
204        } else if (value instanceof Byte) {
205            number = ((Byte) value).byteValue();
206        } else if (value instanceof Short) {
207            number = ((Short) value).shortValue();
208        } else if (value instanceof Integer) {
209            number = ((Integer) value).intValue();
210        } else if (value instanceof Long) {
211            number = ((Long) value).longValue();
212        } else {
213            throw new IllegalArgumentException("Unsupported value class: " + value.getClass().getName());
214        }
215        return number;
216    }
217 
218    /**
219     * Add a timestamp string to a given string. This is used in the GUI and I'm not sure why it is defined here.
220     *
221     * @param text    textarea string to insert to
222     * @param origPos current position of the cursor
223     *
224     * @return new string to use in the text area
225     */
226    public static String addTimeStampToTextArea(final String text, final int origPos) {
227        //todo move this to a GUI class
228        //todo fix the case of adding time stamp to EOLN, EOLN, EOF (adding
229        final String newText;
230        if (text.length() == 0) { // special empty case
231            newText = "[00:00]";
232        } else {
233            int i = origPos;
234            i = Math.min(i, text.length() - 1); // if at end of whole string
235            if (text.charAt(i) == '\n') {
236                i--; // if at the end of line
237            }
238            for (; i > 0; i--) {
239                if (text.charAt(i) == '\n') {
240                    break;
241                }
242            }
243            if (i == 0) { // if at very first character
244                newText = "[00:00]" + text;
245            } else {
246                i++;
247                final String before = text.substring(0, i);
248                final String after = text.substring(i);
249                newText = before + "[00:00]" + after;
250            }
251        }
252        return newText;
253    }
254 
255    public static String appendBeforeExtension(final String filename, final String addition) {
256        if (addition == null) {
257            return filename;
258        }
259        if (filename == null) {
260            return addition;
261        }
262        final int index = filename.lastIndexOf('.');
263        if (index < 0) {
264            return filename + addition;
265        }
266        return filename.substring(0, index) + addition + filename.substring(index);
267    }
268 
269    public static String convertFrameID2_2to2_3(final String identifier) {
270        if (identifier == null) {
271            throw new NullPointerException("Identifier is null");
272        }
273        if (identifier.length() < 3) {
274            return null;
275        }
276        return (String) TagConstant.id3v2_2ToId3v2_3.get(identifier.subSequence(0, 3));
277    }
278 
279    public static String convertFrameID2_2to2_4(final String identifier) {
280        if (identifier == null) {
281            throw new NullPointerException("Identifier is null");
282        }
283        if (identifier.length() < 3) {
284            return null;
285        }
286        String id = (String) TagConstant.id3v2_2ToId3v2_3.get(identifier.substring(0, 3));
287        if (id != null) {
288            id = (String) TagConstant.id3v2_3ToId3v2_4.get(id);
289        }
290        return id;
291    }
292 
293    public static String convertFrameID2_3to2_2(final String identifier) {
294        if (identifier == null) {
295            throw new NullPointerException("Identifier is null");
296        }
297        if (identifier.length() < 4) {
298            return null;
299        }
300        return (String) TagConstant.id3v2_3ToId3v2_2.get(identifier.substring(0, 4));
301    }
302 
303    public static String convertFrameID2_3to2_4(final String identifier) {
304        if (identifier == null) {
305            throw new NullPointerException("Identifier is null");
306        }
307        if (identifier.length() < 4) {
308            return null;
309        }
310        return (String) TagConstant.id3v2_3ToId3v2_4.get(identifier.substring(0, 4));
311    }
312 
313    public static String convertFrameID2_4to2_2(final String identifier) {
314        if (identifier == null) {
315            throw new NullPointerException("Identifier is null");
316        }
317        if (identifier.length() < 4) {
318            return null;
319        }
320        String id = (String) TagConstant.id3v2_4ToId3v2_3.get(identifier.substring(0, 4));
321        if (id != null) {
322            id = (String) TagConstant.id3v2_3ToId3v2_2.get(id);
323        }
324        return id;
325    }
326 
327    public static String convertFrameID2_4to2_3(final String identifier) {
328        if (identifier == null) {
329            throw new NullPointerException("Identifier is null");
330        }
331        if (identifier.length() < 4) {
332            return null;
333        }
334        return (String) TagConstant.id3v2_4ToId3v2_3.get(identifier);
335    }
336 
337    /**
338     * Copy the source file to the destination file. The destination file will be deleted first before copying starts.
339     */
340    public static void copyFile(final File source, final File destination) throws FileNotFoundException, IOException {
341        if (source == null) {
342            throw new NullPointerException("Source is null");
343        }
344        if (destination == null) {
345            throw new NullPointerException("Destination is null");
346        }
347        if (source.exists() == false) {
348            throw new NullPointerException("Source file not found.");
349        }
350        FileInputStream fio = null;
351        BufferedInputStream bio = null;
352        FileOutputStream fos = null;
353        BufferedOutputStream bos = null;
354        final byte[] buffer;
355        try {
356            if (destination.exists()) {
357                destination.delete();
358            }
359            fio = new FileInputStream(source);
360            bio = new BufferedInputStream(fio);
361            fos = new FileOutputStream(destination);
362            bos = new BufferedOutputStream(fos);
363            buffer = new byte[1024];
364            int b = bio.read(buffer);
365            while (b != -1) {
366                bos.write(buffer, 0, b);
367                b = bio.read(buffer);
368            }
369        } finally {
370            if (bio != null) {
371                bio.close();
372            }
373            if (bos != null) {
374                bos.flush();
375                bos.close();
376            }
377            if (fos != null) {
378                fos.close();
379            }
380            if (fio != null) {
381                fio.close();
382            }
383        }
384    }
385 
386    /**
387     * Unable to instantiate abstract classes, so can't call the copy constructor. So find out the instianted class name
388     * and call the copy constructor through reflection.
389     */
390    public static Object copyObject(final Object copyObject) {
391        final Constructor constructor;
392        final Class[] constructorParameterArray;
393        final Object[] parameterArray;
394        if (copyObject == null) {
395            return null;
396        }
397        try {
398            constructorParameterArray = new Class[1];
399            constructorParameterArray[0] = copyObject.getClass();
400            constructor = copyObject.getClass().getConstructor(constructorParameterArray);
401            parameterArray = new Object[1];
402            parameterArray[0] = copyObject;
403            return constructor.newInstance(parameterArray);
404        } catch (NoSuchMethodException ex) {
405            throw new IllegalArgumentException("NoSuchMethodException: Error finding constructor to create copy");
406        } catch (IllegalAccessException ex) {
407            throw new IllegalArgumentException("IllegalAccessException: No access to run constructor to create copy");
408        } catch (InstantiationException ex) {
409            throw new IllegalArgumentException("InstantiationException: Unable to instantiate constructor to copy");
410        } catch (java.lang.reflect.InvocationTargetException ex) {
411            throw new IllegalArgumentException("InvocationTargetException: Unable to invoke constructor to create copy");
412        }
413    }
414 
415    /**
416     * return the index of the matching of parenthesis. This will match all four parenthesis and enclosed parenthesis.
417     *
418     * @param str   string to search
419     * @param index index of string to start searching. This index should point to the opening parenthesis.
420     *
421     * @return index of the matching parenthesis. -1 is returned if none is found, or if the parenthesis are
422     *         unbalanced.
423     */
424    public static int findMatchingParenthesis(final String str, final int index) {
425        if (str == null) {
426            throw new NullPointerException("String is null");
427        }
428        if ((index < 0) || (index >= str.length())) {
429            throw new IndexOutOfBoundsException("Index to image string is out of bounds: offset = " +
430                                                index +
431                                                ", string.length()" +
432                                                str.length());
433        }
434        final TagOptionSingleton option = TagOptionSingleton.getInstance();
435        final Stack stack = new Stack();
436        String chString;
437        String open;
438        char ch;
439        if (index >= 0) {
440            final int length = str.length();
441            if (length == 0) {
442                return 0;
443            }
444            for (int i = index; i < length; i++) {
445                ch = str.charAt(i);
446                chString = ch + "";
447                if (option.isOpenParenthesis(chString)) {
448                    stack.push(chString);
449                }
450                if (option.isCloseParenthesis(chString)) {
451                    if (stack.size() <= 0) {
452                        return -1;
453                    }
454                    open = (String) stack.pop();
455                    if (option.getCloseParenthesis(open).equals(chString) == false) {
456                        return -1;
457                    }
458                }
459                if (stack.size() <= 0) {
460                    return i;
461                }
462            }
463        }
464        return -1;
465    }
466 
467    /**
468     * Find the first whole number that can be parsed from the string
469     *
470     * @param str string to search
471     *
472     * @return first whole number that can be parsed from the string
473     */
474    public static long findNumber(final String str) throws TagException {
475        return findNumber(str, 0);
476    }
477 
478    /**
479     * Find the first whole number that can be parsed from the string
480     *
481     * @param str    string to search
482     * @param offset start seaching from this index
483     *
484     * @return first whole number that can be parsed from the string
485     */
486    public static long findNumber(final String str, final int offset) throws TagException {
487        if (str == null) {
488            throw new NullPointerException("String is null");
489        }
490        if ((offset < 0) || (offset >= str.length())) {
491            throw new IndexOutOfBoundsException("Offset to image string is out of bounds: offset = " +
492                                                offset +
493                                                ", string.length()" +
494                                                str.length());
495        }
496        int i;
497        int j;
498        final long num;
499        i = offset;
500        while (i < str.length()) {
501            if (((str.charAt(i) >= '0') && (str.charAt(i) <= '9')) || (str.charAt(i) == '-')) {
502                break;
503            }
504            i++;
505        }
506        j = i + 1;
507        while (j < str.length()) {
508            if (((str.charAt(j) < '0') || (str.charAt(j) > '9'))) {
509                break;
510            }
511            j++;
512        }
513        if ((j <= str.length()) && (j > i)) {
514            num = Long.parseLong(str.substring(i, j));
515        } else {
516            throw new TagException("Unable to find integer in string: " + str);
517        }
518        return num;
519    }
520 
521    /**
522     * String formatting function to pad the given string with the given character
523     *
524     * @param str       string to pad
525     * @param length    total length of new string
526     * @param ch        character to pad the string with
527     * @param padBefore if true, add the padding at the start of the string. if false, add the padding at the end of the
528     *                  string.
529     *
530     * @return new padded string.
531     */
532    public static String padString(final String str, final int length, final char ch, final boolean padBefore) {
533        if (length < 0) {
534            return str;
535        } else if (length == 0) {
536            if (str == null) {
537                return "";
538            }
539            return str;
540        }
541        int strLength = 0;
542        if (str != null) {
543            strLength = str.length();
544        }
545        if (strLength >= length) {
546            return str;
547        }
548        final char[] buffer = new char[length];
549        int next = 0;
550        if (padBefore) {
551            for (int i = 0; i < (length - strLength); i++) {
552                buffer[next++] = ch;
553            }
554        }
555        if (str != null) {
556            for (int i = 0; i < strLength; i++) {
557                buffer[next++] = str.charAt(i);
558            }
559        }
560        if (padBefore == false) {
561            for (int i = 0; i < (length - strLength); i++) {
562                buffer[next++] = ch;
563            }
564        }
565        return new String(buffer);
566    }
567 
568    /**
569     * Replace the Unix end of line character with the DOS end of line character.
570     *
571     * @param text string to search and replace
572     *
573     * @return replaced string
574     */
575    public static String replaceEOLNwithCRLF(final String text) {
576        String newText = null;
577        if (text != null) {
578            newText = "";
579            int oldPos = 0;
580            int newPos = text.indexOf('\n');
581            while (newPos >= 0) {
582                newText += (text.substring(oldPos, newPos) + TagConstant.SEPERATOR_LINE);
583                oldPos = newPos + 1;
584                newPos = text.indexOf('\n', oldPos);
585            }
586            newText += text.substring(oldPos);
587        }
588        return newText;
589    }
590 
591    /**
592     * Search the <code>source</code> string for any occurance of <code>oldString</code> and replaced them all with
593     * <code>newString</code>. This searches for the entire word of old string. A blank space is appended to the front
594     * and back of <code>oldString</code>
595     */
596    public static String replaceWord(String source, final String oldString, String newString) {
597        if (source == null) {
598            throw new NullPointerException("Source is null");
599        }
600        if (oldString == null) {
601            throw new NullPointerException("Old string (string to be replaced) is null");
602        }
603        if ((source.length() > 0) && (oldString.length() > 0)) {
604            if (newString == null) {
605                newString = "";
606            }
607            final StringBuffer str = new StringBuffer(source);
608            int index = str.indexOf(oldString);
609            final int length = oldString.length();
610            while (index >= 0) {
611                if (((index == 0) && Character.isWhitespace(str.charAt(index + length))) ||
612                    (Character.isWhitespace(str.charAt(index - 1)) && ((index + length) >= str.length())) ||
613                    (Character.isWhitespace(str.charAt(index - 1)) &&
614                     Character.isWhitespace(str.charAt(index + length)))) {
615                    str.replace(index, index + length, newString);
616                }
617                index = str.indexOf(oldString, index);
618            }
619            source = str.toString();
620        }
621        return source;
622    }
623 
624    /**
625     * Remove all occurances of the given character from the string argument.
626     *
627     * @param str String to search
628     * @param ch  character to remove
629     *
630     * @return new String without the given charcter
631     */
632    public static String stripChar(final String str, final char ch) {
633        if (str == null) {
634            throw new NullPointerException("String is null");
635        }
636        final char[] buffer = new char[str.length()];
637        int next = 0;
638        for (int i = 0; i < str.length(); i++) {
639            if (str.charAt(i) != ch) {
640                buffer[next++] = str.charAt(i);
641            }
642        }
643        return new String(buffer, 0, next);
644    }
645 
646    /**
647     * Change the given string into sentence case. Sentence case has the first words always capitalized. Any words in
648     * <code>TagConstants.upperLowerCase</code> will be capitalized that way. Any other words will be turned lower
649     * case.
650     *
651     * @param str           String to modify
652     * @param keepUppercase if true, keep a word if it is already all in UPPERCASE
653     *
654     * @return new string in sentence case.
655     */
656    public static String toSentenceCase(final String str, final boolean keepUppercase) {
657        if (str == null) {
658            throw new NullPointerException("String is null");
659        }
660        final StringTokenizer tokenizer = new StringTokenizer(str);
661        String token;
662        final int numberTokens = tokenizer.countTokens();
663        int countedTokens = 0;
664        final StringBuffer newString = new StringBuffer();
665 
666        // Capitalize first word of all sentences.
667        if (tokenizer.hasMoreTokens()) {
668            token = tokenizer.nextToken();
669            newString.append(capitalizeWord(token, keepUppercase));
670            newString.append(' ');
671            countedTokens++;
672        }
673 
674        // go through all remainder tokens
675        while (tokenizer.hasMoreTokens() && (countedTokens < numberTokens)) {
676            token = tokenizer.nextToken();
677            countedTokens++;
678            if (capitalizationMap.containsKey(token.toLowerCase())) {
679                newString.append(capitalizationMap.get(token.toLowerCase()));
680            } else if (keepUppercase && token.toUpperCase().equals(token)) {
681                newString.append(token);
682            } else {
683                newString.append(token.toLowerCase());
684            }
685            newString.append(' ');
686        }
687 
688        // remove trailing space
689        if (newString.length() > 0) {
690            newString.deleteCharAt(newString.length() - 1);
691        }
692        return newString.toString();
693    }
694 
695    /**
696     * Change the given string to title case. The first and last words of the string are always capitilized. Any words
697     * in <code>TagConstants.upperLowerCase</code> will be capitalized that way. Any other words will be capitalized.
698     *
699     * @param str           String to modify
700     * @param keepUppercase if true, keep a word if it is already all in UPPERCASE
701     *
702     * @return new capitlized string.
703     */
704    public static String toTitleCase(final String str, final boolean keepUppercase) {
705        if (str == null) {
706            throw new NullPointerException("String is null");
707        }
708        final StringTokenizer tokenizer = new StringTokenizer(str);
709        String token;
710        final int numberTokens = tokenizer.countTokens();
711        int countedTokens = 0;
712        final StringBuffer newString = new StringBuffer();
713 
714        // Capitalize first word of all titles.
715        if (tokenizer.hasMoreTokens()) {
716            token = tokenizer.nextToken();
717            newString.append(capitalizeWord(token, keepUppercase));
718            newString.append(' ');
719            countedTokens++;
720        }
721 
722        // go through all remainder tokens except last
723        while (tokenizer.hasMoreTokens() && (countedTokens < (numberTokens - 1))) {
724            token = tokenizer.nextToken();
725            countedTokens++;
726            if (capitalizationMap.containsKey(token.toLowerCase())) {
727                newString.append(capitalizationMap.get(token.toLowerCase()));
728            } else {
729                newString.append(capitalizeWord(token, keepUppercase));
730            }
731            newString.append(' ');
732        }
733 
734        // Capitalize last word of all titles.
735        if (tokenizer.hasMoreTokens()) {
736            token = tokenizer.nextToken();
737            newString.append(capitalizeWord(token, keepUppercase));
738            newString.append(' ');
739        }
740 
741        // remove trailing space
742        if (newString.length() > 0) {
743            newString.deleteCharAt(newString.length() - 1);
744        }
745        return newString.toString();
746    }
747 
748    /**
749     * truncate a string if it longer than the argument
750     *
751     * @param str String to truncate
752     * @param len maximum desired length of new string
753     */
754    public static String truncate(final String str, final int len) {
755        if (str == null) {
756            throw new NullPointerException("String is null");
757        }
758        if (len < 0) {
759            throw new IndexOutOfBoundsException("Length is less than zero");
760        }
761        if (str.length() > len) {
762            return str.substring(0, len);
763        }
764        return str.trim();
765    }
766 
767    /**
768     * Capitalize the word with the first letter upper case and all others lower case.
769     *
770     * @param word          word to capitalize.
771     * @param keepUppercase if true, keep a word if it is already all in UPPERCASE
772     *
773     * @return new capitalized word.
774     */
775    private static StringBuffer capitalizeWord(String word, final boolean keepUppercase) {
776        if (word == null) {
777            return null;
778        }
779        final StringBuffer wordBuffer = new StringBuffer();
780        int index = 0;
781        if (keepUppercase && word.toUpperCase().equals(word)) {
782            wordBuffer.append(word);
783        } else {
784            word = word.toLowerCase();
785            final int len = word.length();
786            char ch;
787            ch = word.charAt(index);
788            while (((ch < 'a') || (ch > 'z')) && (index < (len - 1))) {
789                ch = word.charAt(++index);
790            }
791            if (index < len) {
792                wordBuffer.append(word.substring(0, index));
793                wordBuffer.append((char) (ch + UPPERCASE));
794                wordBuffer.append(word.substring(index + 1));
795            } else {
796                wordBuffer.append(word);
797            }
798        }
799        return wordBuffer;
800    }
801}

[all classes][org.farng.mp3]
EMMA 2.0.5312 (C) Vladimir Roubtsov