Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
StringUtils |
|
| 7.0;7 |
1 | package org.apache.maven.surefire.util.internal; | |
2 | ||
3 | /* | |
4 | * Licensed to the Apache Software Foundation (ASF) under one | |
5 | * or more contributor license agreements. See the NOTICE file | |
6 | * distributed with this work for additional information | |
7 | * regarding copyright ownership. The ASF licenses this file | |
8 | * to you under the Apache License, Version 2.0 (the | |
9 | * "License"); you may not use this file except in compliance | |
10 | * with the License. You may obtain a copy of the License at | |
11 | * | |
12 | * http://www.apache.org/licenses/LICENSE-2.0 | |
13 | * | |
14 | * Unless required by applicable law or agreed to in writing, | |
15 | * software distributed under the License is distributed on an | |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
17 | * KIND, either express or implied. See the License for the | |
18 | * specific language governing permissions and limitations | |
19 | * under the License. | |
20 | */ | |
21 | ||
22 | import java.util.StringTokenizer; | |
23 | ||
24 | /** | |
25 | * <p> | |
26 | * Common <code>String</code> manipulation routines. | |
27 | * </p> | |
28 | * <p/> | |
29 | * <p> | |
30 | * Originally from <a href="http://jakarta.apache.org/turbine/">Turbine</a> and the GenerationJavaCore library. | |
31 | * </p> | |
32 | * | |
33 | * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> | |
34 | * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> | |
35 | * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a> | |
36 | * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a> | |
37 | * @author <a href="mailto:ed@codehaus.org">Ed Korthof</a> | |
38 | * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a> | |
39 | * @author Stephen Colebourne | |
40 | * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a> | |
41 | * @author Holger Krauth | |
42 | * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a> | |
43 | * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> | |
44 | * @version $Id: StringUtils.java 8001 2009-01-03 13:17:09Z vsiveton $ | |
45 | * @noinspection JavaDoc | |
46 | * <p/> | |
47 | * A quick borrow from plexus-utils by Kristian Rosenvold, to restore jdk1.3 compat Threw away all the | |
48 | * unused stuff. | |
49 | * <p/> | |
50 | * NOTE: This class is not part of any api and is public purely for technical reasons ! | |
51 | * @since 1.0 | |
52 | */ | |
53 | 0 | public class StringUtils |
54 | { | |
55 | 1 | private static final byte[] HEX_CHARS = new byte[] { |
56 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
57 | 'A', 'B', 'C', 'D', 'E', 'F' }; | |
58 | ||
59 | public static String[] split( String text, String separator ) | |
60 | { | |
61 | 2 | int max = -1; |
62 | StringTokenizer tok; | |
63 | 2 | if ( separator == null ) |
64 | { | |
65 | // Null separator means we're using StringTokenizer's default | |
66 | // delimiter, which comprises all whitespace characters. | |
67 | 0 | tok = new StringTokenizer( text ); |
68 | } | |
69 | else | |
70 | { | |
71 | 2 | tok = new StringTokenizer( text, separator ); |
72 | } | |
73 | ||
74 | 2 | int listSize = tok.countTokens(); |
75 | 2 | if ( ( max > 0 ) && ( listSize > max ) ) |
76 | { | |
77 | 0 | listSize = max; |
78 | } | |
79 | ||
80 | 2 | String[] list = new String[listSize]; |
81 | 2 | int i = 0; |
82 | int lastTokenBegin; | |
83 | 2 | int lastTokenEnd = 0; |
84 | 65 | while ( tok.hasMoreTokens() ) |
85 | { | |
86 | 63 | if ( ( max > 0 ) && ( i == listSize - 1 ) ) |
87 | { | |
88 | // In the situation where we hit the max yet have | |
89 | // tokens left over in our input, the last list | |
90 | // element gets all remaining text. | |
91 | 0 | String endToken = tok.nextToken(); |
92 | 0 | lastTokenBegin = text.indexOf( endToken, lastTokenEnd ); |
93 | 0 | list[i] = text.substring( lastTokenBegin ); |
94 | 0 | break; |
95 | } | |
96 | else | |
97 | { | |
98 | 63 | list[i] = tok.nextToken(); |
99 | 63 | lastTokenBegin = text.indexOf( list[i], lastTokenEnd ); |
100 | 63 | lastTokenEnd = lastTokenBegin + list[i].length(); |
101 | } | |
102 | 63 | i++; |
103 | } | |
104 | 2 | return list; |
105 | } | |
106 | ||
107 | /** | |
108 | * <p> | |
109 | * Checks if a (trimmed) String is <code>null</code> or blank. | |
110 | * </p> | |
111 | * | |
112 | * @param str the String to check | |
113 | * @return <code>true</code> if the String is <code>null</code>, or length zero once trimmed | |
114 | */ | |
115 | public static boolean isBlank( String str ) | |
116 | { | |
117 | 0 | return ( ( str == null ) || ( str.trim().length() == 0 ) ); |
118 | } | |
119 | ||
120 | /** | |
121 | * Escape the specified string to a representation that only consists of nicely printable characters, without any | |
122 | * newlines and without a comma. | |
123 | * <p> | |
124 | * The reverse-method is {@link #unescapeString(StringBuilder, CharSequence)}. | |
125 | * | |
126 | * @param target target string buffer. The required space will be up to {@code str.getBytes().length * 5} chars. | |
127 | * @param str String to escape values in, may be {@code null}. | |
128 | */ | |
129 | public static void escapeToPrintable( StringBuilder target, CharSequence str ) | |
130 | { | |
131 | 125 | if ( target == null ) |
132 | { | |
133 | 0 | throw new IllegalArgumentException( "The target buffer must not be null" ); |
134 | } | |
135 | 125 | if ( str == null ) |
136 | { | |
137 | 0 | return; |
138 | } | |
139 | ||
140 | 2166222 | for ( int i = 0; i < str.length(); i++ ) { |
141 | 2166097 | char c = str.charAt( i ); |
142 | ||
143 | // handle non-nicely printable chars and the comma | |
144 | 2166097 | if ( c < 32 || c > 126 || c == '\\' || c == ',' ) |
145 | { | |
146 | 2162791 | target.append( '\\' ); |
147 | 2162791 | target.append( (char) HEX_CHARS[( 0xF000 & c ) >> 12] ); |
148 | 2162791 | target.append( (char) HEX_CHARS[( 0x0F00 & c ) >> 8] ); |
149 | 2162791 | target.append( (char) HEX_CHARS[( 0x00F0 & c ) >> 4] ); |
150 | 2162791 | target.append( (char) HEX_CHARS[( 0x000F & c )] ); |
151 | } | |
152 | else | |
153 | { | |
154 | 3306 | target.append( c ); |
155 | } | |
156 | } | |
157 | 125 | } |
158 | ||
159 | /** | |
160 | * Reverses the effect of {@link #escapeToPrintable(StringBuilder, CharSequence)}. | |
161 | * | |
162 | * @param target target string buffer | |
163 | * @param str the String to un-escape, as created by {@link #escapeToPrintable(StringBuilder, CharSequence)} | |
164 | */ | |
165 | public static void unescapeString( StringBuilder target, CharSequence str ) | |
166 | { | |
167 | 1 | if ( target == null ) |
168 | { | |
169 | 0 | throw new IllegalArgumentException( "The target buffer must not be null" ); |
170 | } | |
171 | 1 | if ( str == null ) |
172 | { | |
173 | 0 | return; |
174 | } | |
175 | ||
176 | 2162687 | for ( int i = 0; i < str.length(); i++ ) |
177 | { | |
178 | 2162686 | char ch = str.charAt( i ); |
179 | ||
180 | 2162686 | if ( ch == '\\' ) |
181 | { | |
182 | 2162593 | target.append( (char) ( |
183 | digit( str.charAt( ++i ) ) << 12 | |
184 | | digit( str.charAt( ++i ) ) << 8 | |
185 | | digit( str.charAt( ++i ) ) << 4 | |
186 | | digit( str.charAt( ++i ) ) | |
187 | ) ); | |
188 | } | |
189 | else | |
190 | { | |
191 | 93 | target.append( ch ); |
192 | } | |
193 | } | |
194 | 1 | } |
195 | ||
196 | private static int digit( char ch ) | |
197 | { | |
198 | 8650698 | if ( ch >= 'a' ) |
199 | { | |
200 | 0 | return 10 + ch - 'a'; |
201 | } | |
202 | 8650698 | else if ( ch >= 'A' ) |
203 | { | |
204 | 5341302 | return 10 + ch - 'A'; |
205 | } | |
206 | else | |
207 | { | |
208 | 3309396 | return ch - '0'; |
209 | } | |
210 | } | |
211 | ||
212 | /** | |
213 | * Escapes the bytes in the array {@code str} to contain only 'printable' bytes. | |
214 | * <p> | |
215 | * Escaping is done by encoding the non-nicely printable bytes to {@code '\' + upperCaseHexBytes(byte)}. | |
216 | * <p> | |
217 | * A save length of {@code out} is {@code len * 3 + outoff}. | |
218 | * <p> | |
219 | * The reverse-method is {@link #unescapeBytes(byte[], String)}. | |
220 | * | |
221 | * @param out output buffer | |
222 | * @param outoff offset in the output buffer | |
223 | * @param input input buffer | |
224 | * @param off offset in the input buffer | |
225 | * @param len number of bytes to copy from the input buffer | |
226 | * @return number of bytes written to {@code out} | |
227 | */ | |
228 | public static int escapeBytesToPrintable( byte[] out, int outoff, byte[] input, int off, int len ) | |
229 | { | |
230 | 1 | if ( out == null ) |
231 | { | |
232 | 0 | throw new IllegalArgumentException( "The output array must not be null" ); |
233 | } | |
234 | 1 | if ( input == null || input.length == 0 ) |
235 | { | |
236 | 0 | return 0; |
237 | } | |
238 | 1 | int outputPos = outoff; |
239 | 1 | int end = off + len; |
240 | 257 | for ( int i = off; i < end; i++ ) |
241 | { | |
242 | 256 | byte b = input[i]; |
243 | ||
244 | // handle non-nicely printable bytes | |
245 | 256 | if ( b < 32 || b > 126 || b == '\\' || b == ',' ) |
246 | { | |
247 | 163 | int upper = ( 0xF0 & b ) >> 4; |
248 | 163 | int lower = ( 0x0F & b ); |
249 | 163 | out[outputPos++] = '\\'; |
250 | 163 | out[outputPos++] = HEX_CHARS[upper]; |
251 | 163 | out[outputPos++] = HEX_CHARS[lower]; |
252 | 163 | } |
253 | else | |
254 | { | |
255 | 93 | out[outputPos++] = b; |
256 | } | |
257 | } | |
258 | ||
259 | 1 | return outputPos - outoff; |
260 | } | |
261 | ||
262 | /** | |
263 | * Reverses the effect of {@link #escapeBytesToPrintable(byte[], int, byte[], int, int)}. | |
264 | * <p> | |
265 | * A save length of {@code out} is {@code str.length()} | |
266 | * | |
267 | * @param out the target byte array | |
268 | * @param str the input String | |
269 | * @return the number of bytes written to {@code out} | |
270 | */ | |
271 | public static int unescapeBytes( byte[] out, String str ) | |
272 | { | |
273 | 1 | int outPos = 0; |
274 | 1 | if ( out == null ) |
275 | { | |
276 | 0 | throw new IllegalArgumentException( "The output array must not be null" ); |
277 | } | |
278 | 1 | if ( str == null ) |
279 | { | |
280 | 0 | return 0; |
281 | } | |
282 | 257 | for ( int i = 0; i < str.length(); i++ ) |
283 | { | |
284 | 256 | char ch = str.charAt( i ); |
285 | ||
286 | 256 | if ( ch == '\\' ) |
287 | { | |
288 | 163 | int upper = digit( str.charAt( ++i ) ); |
289 | 163 | int lower = digit( str.charAt( ++i ) ); |
290 | 163 | out[outPos++] = (byte) ( upper << 4 | lower ); |
291 | 163 | } |
292 | else | |
293 | { | |
294 | 93 | out[outPos++] = (byte) ch; |
295 | } | |
296 | } | |
297 | 1 | return outPos; |
298 | } | |
299 | } |