EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.util]

COVERAGE SUMMARY FOR SOURCE FILE [StringUtils.java]

nameclass, %method, %block, %line, %
StringUtils.java100% (1/1)96%  (45/47)94%  (1716/1819)92%  (378.6/412)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class StringUtils100% (1/1)96%  (45/47)94%  (1716/1819)92%  (378.6/412)
StringUtils (): void 0%   (0/1)0%   (0/3)0%   (0/2)
getFormatException (String, int): DbException 0%   (0/1)0%   (0/6)0%   (0/1)
urlEncode (String): String 100% (1/1)50%  (4/8)33%  (1/3)
javaDecode (String): String 100% (1/1)75%  (114/152)70%  (32/46)
urlDecode (String): String 100% (1/1)82%  (72/88)94%  (15/16)
escapeMetaDataPattern (String): String 100% (1/1)83%  (10/12)67%  (2/3)
xmlText (String, boolean): String 100% (1/1)84%  (76/91)76%  (19/25)
getCache (): String [] 100% (1/1)88%  (38/43)98%  (10.7/11)
cloneCharArray (char []): char [] 100% (1/1)91%  (20/22)88%  (7/8)
isNumber (String): boolean 100% (1/1)93%  (27/29)83%  (5/6)
cache (String): String 100% (1/1)95%  (42/44)94%  (15/16)
fromCacheOrNew (String): String 100% (1/1)96%  (49/51)94%  (17/18)
arrayCombine (String [], char): String 100% (1/1)97%  (57/59)91%  (10/11)
pad (String, int, String, boolean): String 100% (1/1)97%  (65/67)94%  (17/18)
trim (String, boolean, boolean, String): String 100% (1/1)97%  (67/69)99%  (12.8/13)
<static initializer> 100% (1/1)100% (61/61)100% (11/11)
addAsterisk (String, int): String 100% (1/1)100% (25/25)100% (4/4)
appendZeroPadded (StringBuilder, int, long): void 100% (1/1)100% (37/37)100% (11/11)
arraySplit (String, char, boolean): String [] 100% (1/1)100% (91/91)100% (21/21)
clearCache (): void 100% (1/1)100% (6/6)100% (2/2)
convertBytesToHex (byte []): String 100% (1/1)100% (5/5)100% (1/1)
convertBytesToHex (byte [], int): String 100% (1/1)100% (47/47)100% (7/7)
convertHexToBytes (String): byte [] 100% (1/1)100% (74/74)100% (17/17)
enclose (String): String 100% (1/1)100% (17/17)100% (3/3)
equals (String, String): boolean 100% (1/1)100% (12/12)100% (3/3)
indent (String): String 100% (1/1)100% (5/5)100% (1/1)
indent (String, int, boolean): String 100% (1/1)100% (62/62)100% (12/12)
isNullOrEmpty (String): boolean 100% (1/1)100% (9/9)100% (1/1)
javaEncode (String): String 100% (1/1)100% (92/92)100% (26/26)
quoteIdentifier (String): String 100% (1/1)100% (41/41)100% (9/9)
quoteJavaIntArray (int []): String 100% (1/1)100% (38/38)100% (7/7)
quoteJavaString (String): String 100% (1/1)100% (16/16)100% (3/3)
quoteJavaStringArray (String []): String 100% (1/1)100% (38/38)100% (7/7)
quoteRemarkSQL (String): String 100% (1/1)100% (10/10)100% (2/2)
quoteStringSQL (String): String 100% (1/1)100% (67/67)100% (14/14)
replaceAll (String, String, String): String 100% (1/1)100% (53/53)100% (12/12)
startsWithIgnoreCase (String, String): boolean 100% (1/1)100% (15/15)100% (3/3)
toLowerEnglish (String): String 100% (1/1)100% (4/4)100% (1/1)
toUpperEnglish (String): String 100% (1/1)100% (50/50)100% (11/11)
unEnclose (String): String 100% (1/1)100% (18/18)100% (3/3)
xmlAttr (String, String): String 100% (1/1)100% (16/16)100% (1/1)
xmlCData (String): String 100% (1/1)100% (35/35)100% (5/5)
xmlComment (String): String 100% (1/1)100% (58/58)100% (8/8)
xmlNode (String, String, String): String 100% (1/1)100% (6/6)100% (1/1)
xmlNode (String, String, String, boolean): String 100% (1/1)100% (61/61)100% (6/6)
xmlStartDoc (): String 100% (1/1)100% (2/2)100% (1/1)
xmlText (String): String 100% (1/1)100% (4/4)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.util;
7 
8import java.lang.ref.SoftReference;
9import java.net.URLEncoder;
10import java.util.ArrayList;
11import java.util.Locale;
12 
13import org.h2.api.ErrorCode;
14import org.h2.engine.Constants;
15import org.h2.engine.SysProperties;
16import org.h2.message.DbException;
17 
18/**
19 * A few String utility functions.
20 */
21public class StringUtils {
22 
23    private static SoftReference<String[]> softCache =
24            new SoftReference<String[]>(null);
25    private static long softCacheCreated;
26 
27    private static final char[] HEX = "0123456789abcdef".toCharArray();
28    private static final int[] HEX_DECODE = new int['f' + 1];
29 
30    // memory used by this cache:
31    // 4 * 1024 * 2 (strings per pair) * 64 * 2 (bytes per char) = 0.5 MB
32    private static final int TO_UPPER_CACHE_LENGTH = 2 * 1024;
33    private static final int TO_UPPER_CACHE_MAX_ENTRY_LENGTH = 64;
34    private static final String[][] TO_UPPER_CACHE = new String[TO_UPPER_CACHE_LENGTH][];
35 
36    static {
37        for (int i = 0; i < HEX_DECODE.length; i++) {
38            HEX_DECODE[i] = -1;
39        }
40        for (int i = 0; i <= 9; i++) {
41            HEX_DECODE[i + '0'] = i;
42        }
43        for (int i = 0; i <= 5; i++) {
44            HEX_DECODE[i + 'a'] = HEX_DECODE[i + 'A'] = i + 10;
45        }
46    }
47 
48    private StringUtils() {
49        // utility class
50    }
51 
52    private static String[] getCache() {
53        String[] cache;
54        // softCache can be null due to a Tomcat problem
55        // a workaround is disable the system property org.apache.
56        // catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES
57        if (softCache != null) {
58            cache = softCache.get();
59            if (cache != null) {
60                return cache;
61            }
62        }
63        // create a new cache at most every 5 seconds
64        // so that out of memory exceptions are not delayed
65        long time = System.currentTimeMillis();
66        if (softCacheCreated != 0 && time - softCacheCreated < 5000) {
67            return null;
68        }
69        try {
70            cache = new String[SysProperties.OBJECT_CACHE_SIZE];
71            softCache = new SoftReference<String[]>(cache);
72            return cache;
73        } finally {
74            softCacheCreated = System.currentTimeMillis();
75        }
76    }
77 
78    /**
79     * Check if two strings are equal. Here, null is equal to null.
80     *
81     * @param a the first value
82     * @param b the second value
83     * @return true if both are null or both are equal
84     */
85    public static boolean equals(String a, String b) {
86        if (a == null) {
87            return b == null;
88        }
89        return a.equals(b);
90    }
91 
92    /**
93     * Convert a string to uppercase using the English locale.
94     *
95     * @param s the test to convert
96     * @return the uppercase text
97     */
98    public static String toUpperEnglish(String s) {
99        if (s.length() > TO_UPPER_CACHE_MAX_ENTRY_LENGTH) {
100            return s.toUpperCase(Locale.ENGLISH);
101        }
102        int index = s.hashCode() & (TO_UPPER_CACHE_LENGTH - 1);
103        String[] e = TO_UPPER_CACHE[index];
104        if (e != null) {
105            if (e[0].equals(s)) {
106                return e[1];
107            }
108        }
109        String s2 = s.toUpperCase(Locale.ENGLISH);
110        e = new String[] { s, s2 };
111        TO_UPPER_CACHE[index] = e;
112        return s2;
113    }
114 
115    /**
116     * Convert a string to lowercase using the English locale.
117     *
118     * @param s the text to convert
119     * @return the lowercase text
120     */
121    public static String toLowerEnglish(String s) {
122        return s.toLowerCase(Locale.ENGLISH);
123    }
124 
125    /**
126     * Check is a string starts with another string, ignoring the case.
127     *
128     * @param s the string to check (must be longer than start)
129     * @param start the prefix of s
130     * @return true if start is a prefix of s
131     */
132    public static boolean startsWithIgnoreCase(String s, String start) {
133        if (s.length() < start.length()) {
134            return false;
135        }
136        return s.substring(0, start.length()).equalsIgnoreCase(start);
137    }
138 
139    /**
140     * Convert a string to a SQL literal. Null is converted to NULL. The text is
141     * enclosed in single quotes. If there are any special characters, the
142     * method STRINGDECODE is used.
143     *
144     * @param s the text to convert.
145     * @return the SQL literal
146     */
147    public static String quoteStringSQL(String s) {
148        if (s == null) {
149            return "NULL";
150        }
151        int length = s.length();
152        StringBuilder buff = new StringBuilder(length + 2);
153        buff.append('\'');
154        for (int i = 0; i < length; i++) {
155            char c = s.charAt(i);
156            if (c == '\'') {
157                buff.append(c);
158            } else if (c < ' ' || c > 127) {
159                // need to start from the beginning because maybe there was a \
160                // that was not quoted
161                return "STRINGDECODE(" + quoteStringSQL(javaEncode(s)) + ")";
162            }
163            buff.append(c);
164        }
165        buff.append('\'');
166        return buff.toString();
167    }
168 
169    /**
170     * Convert a string to a Java literal using the correct escape sequences.
171     * The literal is not enclosed in double quotes. The result can be used in
172     * properties files or in Java source code.
173     *
174     * @param s the text to convert
175     * @return the Java representation
176     */
177    public static String javaEncode(String s) {
178        int length = s.length();
179        StringBuilder buff = new StringBuilder(length);
180        for (int i = 0; i < length; i++) {
181            char c = s.charAt(i);
182            switch (c) {
183//            case '\b':
184//                // BS backspace
185//                // not supported in properties files
186//                buff.append("\\b");
187//                break;
188            case '\t':
189                // HT horizontal tab
190                buff.append("\\t");
191                break;
192            case '\n':
193                // LF linefeed
194                buff.append("\\n");
195                break;
196            case '\f':
197                // FF form feed
198                buff.append("\\f");
199                break;
200            case '\r':
201                // CR carriage return
202                buff.append("\\r");
203                break;
204            case '"':
205                // double quote
206                buff.append("\\\"");
207                break;
208            case '\\':
209                // backslash
210                buff.append("\\\\");
211                break;
212            default:
213                int ch = c & 0xffff;
214                if (ch >= ' ' && (ch < 0x80)) {
215                    buff.append(c);
216                // not supported in properties files
217                // } else if (ch < 0xff) {
218                // buff.append("\\");
219                // // make sure it's three characters (0x200 is octal 1000)
220                // buff.append(Integer.toOctalString(0x200 | ch).substring(1));
221                } else {
222                    buff.append("\\u");
223                    String hex = Integer.toHexString(ch);
224                    // make sure it's four characters
225                    for (int len = hex.length(); len < 4; len++) {
226                        buff.append('0');
227                    }
228                    buff.append(hex);
229                }
230            }
231        }
232        return buff.toString();
233    }
234 
235    /**
236     * Add an asterisk ('[*]') at the given position. This format is used to
237     * show where parsing failed in a statement.
238     *
239     * @param s the text
240     * @param index the position
241     * @return the text with asterisk
242     */
243    public static String addAsterisk(String s, int index) {
244        if (s != null) {
245            index = Math.min(index, s.length());
246            s = s.substring(0, index) + "[*]" + s.substring(index);
247        }
248        return s;
249    }
250 
251    private static DbException getFormatException(String s, int i) {
252        return DbException.get(ErrorCode.STRING_FORMAT_ERROR_1, addAsterisk(s, i));
253    }
254 
255    /**
256     * Decode a text that is encoded as a Java string literal. The Java
257     * properties file format and Java source code format is supported.
258     *
259     * @param s the encoded string
260     * @return the string
261     */
262    public static String javaDecode(String s) {
263        int length = s.length();
264        StringBuilder buff = new StringBuilder(length);
265        for (int i = 0; i < length; i++) {
266            char c = s.charAt(i);
267            if (c == '\\') {
268                if (i + 1 >= s.length()) {
269                    throw getFormatException(s, i);
270                }
271                c = s.charAt(++i);
272                switch (c) {
273                case 't':
274                    buff.append('\t');
275                    break;
276                case 'r':
277                    buff.append('\r');
278                    break;
279                case 'n':
280                    buff.append('\n');
281                    break;
282                case 'b':
283                    buff.append('\b');
284                    break;
285                case 'f':
286                    buff.append('\f');
287                    break;
288                case '#':
289                    // for properties files
290                    buff.append('#');
291                    break;
292                case '=':
293                    // for properties files
294                    buff.append('=');
295                    break;
296                case ':':
297                    // for properties files
298                    buff.append(':');
299                    break;
300                case '"':
301                    buff.append('"');
302                    break;
303                case '\\':
304                    buff.append('\\');
305                    break;
306                case 'u': {
307                    try {
308                        c = (char) (Integer.parseInt(s.substring(i + 1, i + 5), 16));
309                    } catch (NumberFormatException e) {
310                        throw getFormatException(s, i);
311                    }
312                    i += 4;
313                    buff.append(c);
314                    break;
315                }
316                default:
317                    if (c >= '0' && c <= '9') {
318                        try {
319                            c = (char) (Integer.parseInt(s.substring(i, i + 3), 8));
320                        } catch (NumberFormatException e) {
321                            throw getFormatException(s, i);
322                        }
323                        i += 2;
324                        buff.append(c);
325                    } else {
326                        throw getFormatException(s, i);
327                    }
328                }
329            } else {
330                buff.append(c);
331            }
332        }
333        return buff.toString();
334    }
335 
336    /**
337     * Convert a string to the Java literal and enclose it with double quotes.
338     * Null will result in "null" (without double quotes).
339     *
340     * @param s the text to convert
341     * @return the Java representation
342     */
343    public static String quoteJavaString(String s) {
344        if (s == null) {
345            return "null";
346        }
347        return "\"" + javaEncode(s) + "\"";
348    }
349 
350    /**
351     * Convert a string array to the Java source code that represents this
352     * array. Null will be converted to 'null'.
353     *
354     * @param array the string array
355     * @return the Java source code (including new String[]{})
356     */
357    public static String quoteJavaStringArray(String[] array) {
358        if (array == null) {
359            return "null";
360        }
361        StatementBuilder buff = new StatementBuilder("new String[]{");
362        for (String a : array) {
363            buff.appendExceptFirst(", ");
364            buff.append(quoteJavaString(a));
365        }
366        return buff.append('}').toString();
367    }
368 
369    /**
370     * Convert an int array to the Java source code that represents this array.
371     * Null will be converted to 'null'.
372     *
373     * @param array the int array
374     * @return the Java source code (including new int[]{})
375     */
376    public static String quoteJavaIntArray(int[] array) {
377        if (array == null) {
378            return "null";
379        }
380        StatementBuilder buff = new StatementBuilder("new int[]{");
381        for (int a : array) {
382            buff.appendExceptFirst(", ");
383            buff.append(a);
384        }
385        return buff.append('}').toString();
386    }
387 
388    /**
389     * Enclose a string with '(' and ')' if this is not yet done.
390     *
391     * @param s the string
392     * @return the enclosed string
393     */
394    public static String enclose(String s) {
395        if (s.startsWith("(")) {
396            return s;
397        }
398        return "(" + s + ")";
399    }
400 
401    /**
402     * Remove enclosing '(' and ')' if this text is enclosed.
403     *
404     * @param s the potentially enclosed string
405     * @return the string
406     */
407    public static String unEnclose(String s) {
408        if (s.startsWith("(") && s.endsWith(")")) {
409            return s.substring(1, s.length() - 1);
410        }
411        return s;
412    }
413 
414    /**
415     * Encode the string as an URL.
416     *
417     * @param s the string to encode
418     * @return the encoded string
419     */
420    public static String urlEncode(String s) {
421        try {
422            return URLEncoder.encode(s, "UTF-8");
423        } catch (Exception e) {
424            // UnsupportedEncodingException
425            throw DbException.convert(e);
426        }
427    }
428 
429    /**
430     * Decode the URL to a string.
431     *
432     * @param encoded the encoded URL
433     * @return the decoded string
434     */
435    public static String urlDecode(String encoded) {
436        int length = encoded.length();
437        byte[] buff = new byte[length];
438        int j = 0;
439        for (int i = 0; i < length; i++) {
440            char ch = encoded.charAt(i);
441            if (ch == '+') {
442                buff[j++] = ' ';
443            } else if (ch == '%') {
444                buff[j++] = (byte) Integer.parseInt(encoded.substring(i + 1, i + 3), 16);
445                i += 2;
446            } else {
447                if (SysProperties.CHECK) {
448                    if (ch > 127 || ch < ' ') {
449                        throw new IllegalArgumentException(
450                                "Unexpected char " + (int) ch + " decoding " + encoded);
451                    }
452                }
453                buff[j++] = (byte) ch;
454            }
455        }
456        String s = new String(buff, 0, j, Constants.UTF8);
457        return s;
458    }
459 
460    /**
461     * Split a string into an array of strings using the given separator. A null
462     * string will result in a null array, and an empty string in a zero element
463     * array.
464     *
465     * @param s the string to split
466     * @param separatorChar the separator character
467     * @param trim whether each element should be trimmed
468     * @return the array list
469     */
470    public static String[] arraySplit(String s, char separatorChar, boolean trim) {
471        if (s == null) {
472            return null;
473        }
474        int length = s.length();
475        if (length == 0) {
476            return new String[0];
477        }
478        ArrayList<String> list = New.arrayList();
479        StringBuilder buff = new StringBuilder(length);
480        for (int i = 0; i < length; i++) {
481            char c = s.charAt(i);
482            if (c == separatorChar) {
483                String e = buff.toString();
484                list.add(trim ? e.trim() : e);
485                buff.setLength(0);
486            } else if (c == '\\' && i < length - 1) {
487                buff.append(s.charAt(++i));
488            } else {
489                buff.append(c);
490            }
491        }
492        String e = buff.toString();
493        list.add(trim ? e.trim() : e);
494        String[] array = new String[list.size()];
495        list.toArray(array);
496        return array;
497    }
498 
499    /**
500     * Combine an array of strings to one array using the given separator
501     * character. A backslash and the separator character and escaped using a
502     * backslash.
503     *
504     * @param list the string array
505     * @param separatorChar the separator character
506     * @return the combined string
507     */
508    public static String arrayCombine(String[] list, char separatorChar) {
509        StatementBuilder buff = new StatementBuilder();
510        for (String s : list) {
511            buff.appendExceptFirst(String.valueOf(separatorChar));
512            if (s == null) {
513                s = "";
514            }
515            for (int j = 0, length = s.length(); j < length; j++) {
516                char c = s.charAt(j);
517                if (c == '\\' || c == separatorChar) {
518                    buff.append('\\');
519                }
520                buff.append(c);
521            }
522        }
523        return buff.toString();
524    }
525 
526    /**
527     * Creates an XML attribute of the form name="value".
528     * A single space is prepended to the name,
529     * so that multiple attributes can be concatenated.
530     * @param name the attribute name
531     * @param value the attribute value
532     * @return the attribute
533     */
534    public static String xmlAttr(String name, String value) {
535        return " " + name + "=\"" + xmlText(value) + "\"";
536    }
537 
538    /**
539     * Create an XML node with optional attributes and content.
540     * The data is indented with 4 spaces if it contains a newline character.
541     *
542     * @param name the element name
543     * @param attributes the attributes (may be null)
544     * @param content the content (may be null)
545     * @return the node
546     */
547    public static String xmlNode(String name, String attributes, String content) {
548        return xmlNode(name, attributes, content, true);
549    }
550 
551    /**
552     * Create an XML node with optional attributes and content. The data is
553     * indented with 4 spaces if it contains a newline character and the indent
554     * parameter is set to true.
555     *
556     * @param name the element name
557     * @param attributes the attributes (may be null)
558     * @param content the content (may be null)
559     * @param indent whether to indent the content if it contains a newline
560     * @return the node
561     */
562    public static String xmlNode(String name, String attributes,
563            String content, boolean indent) {
564        String start = attributes == null ? name : name + attributes;
565        if (content == null) {
566            return "<" + start + "/>\n";
567        }
568        if (indent && content.indexOf('\n') >= 0) {
569            content = "\n" + indent(content);
570        }
571        return "<" + start + ">" + content + "</" + name + ">\n";
572    }
573 
574    /**
575     * Indents a string with 4 spaces.
576     *
577     * @param s the string
578     * @return the indented string
579     */
580    public static String indent(String s) {
581        return indent(s, 4, true);
582    }
583 
584    /**
585     * Indents a string with spaces.
586     *
587     * @param s the string
588     * @param spaces the number of spaces
589     * @param newline append a newline if there is none
590     * @return the indented string
591     */
592    public static String indent(String s, int spaces, boolean newline) {
593        StringBuilder buff = new StringBuilder(s.length() + spaces);
594        for (int i = 0; i < s.length();) {
595            for (int j = 0; j < spaces; j++) {
596                buff.append(' ');
597            }
598            int n = s.indexOf('\n', i);
599            n = n < 0 ? s.length() : n + 1;
600            buff.append(s.substring(i, n));
601            i = n;
602        }
603        if (newline && !s.endsWith("\n")) {
604            buff.append('\n');
605        }
606        return buff.toString();
607    }
608 
609    /**
610     * Escapes a comment.
611     * If the data contains '--', it is converted to '- -'.
612     * The data is indented with 4 spaces if it contains a newline character.
613     *
614     * @param data the comment text
615     * @return <!-- data -->
616     */
617    public static String xmlComment(String data) {
618        int idx = 0;
619        while (true) {
620            idx = data.indexOf("--", idx);
621            if (idx < 0) {
622                break;
623            }
624            data = data.substring(0, idx + 1) + " " + data.substring(idx + 1);
625        }
626        // must have a space at the beginning and at the end,
627        // otherwise the data must not contain '-' as the first/last character
628        if (data.indexOf('\n') >= 0) {
629            return "<!--\n" + indent(data) + "-->\n";
630        }
631        return "<!-- " + data + " -->\n";
632    }
633 
634    /**
635     * Converts the data to a CDATA element.
636     * If the data contains ']]>', it is escaped as a text element.
637     *
638     * @param data the text data
639     * @return <![CDATA[data]]>
640     */
641    public static String xmlCData(String data) {
642        if (data.contains("]]>")) {
643            return xmlText(data);
644        }
645        boolean newline = data.endsWith("\n");
646        data = "<![CDATA[" + data + "]]>";
647        return newline ? data + "\n" : data;
648    }
649 
650    /**
651     * Returns <?xml version="1.0"?>
652     * @return <?xml version="1.0"?>
653     */
654    public static String xmlStartDoc() {
655        return "<?xml version=\"1.0\"?>\n";
656    }
657 
658    /**
659     * Escapes an XML text element.
660     *
661     * @param text the text data
662     * @return the escaped text
663     */
664    public static String xmlText(String text) {
665        return xmlText(text, false);
666    }
667 
668    /**
669     * Escapes an XML text element.
670     *
671     * @param text the text data
672     * @param escapeNewline whether to escape newlines
673     * @return the escaped text
674     */
675    public static String xmlText(String text, boolean escapeNewline) {
676        int length = text.length();
677        StringBuilder buff = new StringBuilder(length);
678        for (int i = 0; i < length; i++) {
679            char ch = text.charAt(i);
680            switch (ch) {
681            case '<':
682                buff.append("&lt;");
683                break;
684            case '>':
685                buff.append("&gt;");
686                break;
687            case '&':
688                buff.append("&amp;");
689                break;
690            case '\'':
691                buff.append("&apos;");
692                break;
693            case '\"':
694                buff.append("&quot;");
695                break;
696            case '\r':
697            case '\n':
698                if (escapeNewline) {
699                    buff.append("&#x").
700                        append(Integer.toHexString(ch)).
701                        append(';');
702                } else {
703                    buff.append(ch);
704                }
705                break;
706            case '\t':
707                buff.append(ch);
708                break;
709            default:
710                if (ch < ' ' || ch > 127) {
711                    buff.append("&#x").
712                        append(Integer.toHexString(ch)).
713                        append(';');
714                } else {
715                    buff.append(ch);
716                }
717            }
718        }
719        return buff.toString();
720    }
721 
722    /**
723     * Replace all occurrences of the before string with the after string.
724     *
725     * @param s the string
726     * @param before the old text
727     * @param after the new text
728     * @return the string with the before string replaced
729     */
730    public static String replaceAll(String s, String before, String after) {
731        int next = s.indexOf(before);
732        if (next < 0) {
733            return s;
734        }
735        StringBuilder buff = new StringBuilder(
736                s.length() - before.length() + after.length());
737        int index = 0;
738        while (true) {
739            buff.append(s.substring(index, next)).append(after);
740            index = next + before.length();
741            next = s.indexOf(before, index);
742            if (next < 0) {
743                buff.append(s.substring(index));
744                break;
745            }
746        }
747        return buff.toString();
748    }
749 
750    /**
751     * Enclose a string with double quotes. A double quote inside the string is
752     * escaped using a double quote.
753     *
754     * @param s the text
755     * @return the double quoted text
756     */
757    public static String quoteIdentifier(String s) {
758        int length = s.length();
759        StringBuilder buff = new StringBuilder(length + 2);
760        buff.append('\"');
761        for (int i = 0; i < length; i++) {
762            char c = s.charAt(i);
763            if (c == '"') {
764                buff.append(c);
765            }
766            buff.append(c);
767        }
768        return buff.append('\"').toString();
769    }
770 
771    /**
772     * Check if a String is null or empty (the length is null).
773     *
774     * @param s the string to check
775     * @return true if it is null or empty
776     */
777    public static boolean isNullOrEmpty(String s) {
778        return s == null || s.length() == 0;
779    }
780 
781    /**
782     * In a string, replace block comment marks with /++ .. ++/.
783     *
784     * @param sql the string
785     * @return the resulting string
786     */
787    public static String quoteRemarkSQL(String sql) {
788        sql = replaceAll(sql, "*/", "++/");
789        return replaceAll(sql, "/*", "/++");
790    }
791 
792    /**
793     * Pad a string. This method is used for the SQL function RPAD and LPAD.
794     *
795     * @param string the original string
796     * @param n the target length
797     * @param padding the padding string
798     * @param right true if the padding should be appended at the end
799     * @return the padded string
800     */
801    public static String pad(String string, int n, String padding, boolean right) {
802        if (n < 0) {
803            n = 0;
804        }
805        if (n < string.length()) {
806            return string.substring(0, n);
807        } else if (n == string.length()) {
808            return string;
809        }
810        char paddingChar;
811        if (padding == null || padding.length() == 0) {
812            paddingChar = ' ';
813        } else {
814            paddingChar = padding.charAt(0);
815        }
816        StringBuilder buff = new StringBuilder(n);
817        n -= string.length();
818        if (right) {
819            buff.append(string);
820        }
821        for (int i = 0; i < n; i++) {
822            buff.append(paddingChar);
823        }
824        if (!right) {
825            buff.append(string);
826        }
827        return buff.toString();
828    }
829 
830    /**
831     * Create a new char array and copy all the data. If the size of the byte
832     * array is zero, the same array is returned.
833     *
834     * @param chars the char array (may be null)
835     * @return a new char array
836     */
837    public static char[] cloneCharArray(char[] chars) {
838        if (chars == null) {
839            return null;
840        }
841        int len = chars.length;
842        if (len == 0) {
843            return chars;
844        }
845        char[] copy = new char[len];
846        System.arraycopy(chars, 0, copy, 0, len);
847        return copy;
848    }
849 
850    /**
851     * Trim a character from a string.
852     *
853     * @param s the string
854     * @param leading if leading characters should be removed
855     * @param trailing if trailing characters should be removed
856     * @param sp what to remove (only the first character is used)
857     *      or null for a space
858     * @return the trimmed string
859     */
860    public static String trim(String s, boolean leading, boolean trailing,
861            String sp) {
862        char space = (sp == null || sp.length() < 1) ? ' ' : sp.charAt(0);
863        if (leading) {
864            int len = s.length(), i = 0;
865            while (i < len && s.charAt(i) == space) {
866                i++;
867            }
868            s = (i == 0) ? s : s.substring(i);
869        }
870        if (trailing) {
871            int endIndex = s.length() - 1;
872            int i = endIndex;
873            while (i >= 0 && s.charAt(i) == space) {
874                i--;
875            }
876            s = i == endIndex ? s : s.substring(0, i + 1);
877        }
878        return s;
879    }
880 
881    /**
882     * Get the string from the cache if possible. If the string has not been
883     * found, it is added to the cache. If there is such a string in the cache,
884     * that one is returned.
885     *
886     * @param s the original string
887     * @return a string with the same content, if possible from the cache
888     */
889    public static String cache(String s) {
890        if (!SysProperties.OBJECT_CACHE) {
891            return s;
892        }
893        if (s == null) {
894            return s;
895        } else if (s.length() == 0) {
896            return "";
897        }
898        int hash = s.hashCode();
899        String[] cache = getCache();
900        if (cache != null) {
901            int index = hash & (SysProperties.OBJECT_CACHE_SIZE - 1);
902            String cached = cache[index];
903            if (cached != null) {
904                if (s.equals(cached)) {
905                    return cached;
906                }
907            }
908            cache[index] = s;
909        }
910        return s;
911    }
912 
913    /**
914     * Get a string from the cache, and if no such string has been found, create
915     * a new one with only this content. This solves out of memory problems if
916     * the string is a substring of another, large string. In Java, strings are
917     * shared, which could lead to memory problems. This avoid such problems.
918     *
919     * @param s the string
920     * @return a string that is guaranteed not be a substring of a large string
921     */
922    public static String fromCacheOrNew(String s) {
923        if (!SysProperties.OBJECT_CACHE) {
924            return s;
925        }
926        if (s == null) {
927            return s;
928        } else if (s.length() == 0) {
929            return "";
930        }
931        int hash = s.hashCode();
932        String[] cache = getCache();
933        int index = hash & (SysProperties.OBJECT_CACHE_SIZE - 1);
934        if (cache == null) {
935            return s;
936        }
937        String cached = cache[index];
938        if (cached != null) {
939            if (s.equals(cached)) {
940                return cached;
941            }
942        }
943        // create a new object that is not shared
944        // (to avoid out of memory if it is a substring of a big String)
945        // (not longer needed for Java 7 update 6 and newer,
946        // but the performance overhead is very small for those
947        // versions where it is not needed)
948        // NOPMD
949        s = new String(s);
950        cache[index] = s;
951        return s;
952    }
953 
954    /**
955     * Clear the cache. This method is used for testing.
956     */
957    public static void clearCache() {
958        softCache = new SoftReference<String[]>(null);
959    }
960 
961    /**
962     * Convert a hex encoded string to a byte array.
963     *
964     * @param s the hex encoded string
965     * @return the byte array
966     */
967    public static byte[] convertHexToBytes(String s) {
968        int len = s.length();
969        if (len % 2 != 0) {
970            throw DbException.get(ErrorCode.HEX_STRING_ODD_1, s);
971        }
972        len /= 2;
973        byte[] buff = new byte[len];
974        int mask = 0;
975        int[] hex = HEX_DECODE;
976        try {
977            for (int i = 0; i < len; i++) {
978                int d = hex[s.charAt(i + i)] << 4 | hex[s.charAt(i + i + 1)];
979                mask |= d;
980                buff[i] = (byte) d;
981            }
982        } catch (ArrayIndexOutOfBoundsException e) {
983            throw DbException.get(ErrorCode.HEX_STRING_WRONG_1, s);
984        }
985        if ((mask & ~255) != 0) {
986            throw DbException.get(ErrorCode.HEX_STRING_WRONG_1, s);
987        }
988        return buff;
989    }
990 
991    /**
992     * Convert a byte array to a hex encoded string.
993     *
994     * @param value the byte array
995     * @return the hex encoded string
996     */
997    public static String convertBytesToHex(byte[] value) {
998        return convertBytesToHex(value, value.length);
999    }
1000 
1001    /**
1002     * Convert a byte array to a hex encoded string.
1003     *
1004     * @param value the byte array
1005     * @param len the number of bytes to encode
1006     * @return the hex encoded string
1007     */
1008    public static String convertBytesToHex(byte[] value, int len) {
1009        char[] buff = new char[len + len];
1010        char[] hex = HEX;
1011        for (int i = 0; i < len; i++) {
1012            int c = value[i] & 0xff;
1013            buff[i + i] = hex[c >> 4];
1014            buff[i + i + 1] = hex[c & 0xf];
1015        }
1016        return new String(buff);
1017    }
1018 
1019    /**
1020     * Check if this string is a decimal number.
1021     *
1022     * @param s the string
1023     * @return true if it is
1024     */
1025    public static boolean isNumber(String s) {
1026        if (s.length() == 0) {
1027            return false;
1028        }
1029        for (char c : s.toCharArray()) {
1030            if (!Character.isDigit(c)) {
1031                return false;
1032            }
1033        }
1034        return true;
1035    }
1036 
1037    /**
1038     * Append a zero-padded number to a string builder.
1039     *
1040     * @param buff the string builder
1041     * @param length the number of characters to append
1042     * @param positiveValue the number to append
1043     */
1044    public static void appendZeroPadded(StringBuilder buff, int length,
1045            long positiveValue) {
1046        if (length == 2) {
1047            if (positiveValue < 10) {
1048                buff.append('0');
1049            }
1050            buff.append(positiveValue);
1051        } else {
1052            String s = Long.toString(positiveValue);
1053            length -= s.length();
1054            while (length > 0) {
1055                buff.append('0');
1056                length--;
1057            }
1058            buff.append(s);
1059        }
1060    }
1061 
1062    /**
1063     * Escape table or schema patterns used for DatabaseMetaData functions.
1064     *
1065     * @param pattern the pattern
1066     * @return the escaped pattern
1067     */
1068    public static String escapeMetaDataPattern(String pattern) {
1069        if (pattern == null || pattern.length() == 0) {
1070            return pattern;
1071        }
1072        return replaceAll(pattern, "\\", "\\\\");
1073    }
1074 
1075}

[all classes][org.h2.util]
EMMA 2.0.5312 (C) Vladimir Roubtsov