Clover Coverage Report - Atlassian Trusted Apps(Aggregated)
Coverage timestamp: Tue Jun 9 2009 19:34:44 CDT
190   484   87   11.18
46   339   0.46   5.67
17     5.12  
3    
 
 
  StringUtil       Line # 23 5 2 100% 1.0
  StringUtil.JSONList       Line # 51 85 36 77.4% 0.7735849
  StringUtil.JSONList.Tokenizer       Line # 216 100 49 41.4% 0.41428572
 
  (43)
 
1    package com.atlassian.security.auth.trustedapps;
2   
3    /*
4    * Portions Copyright (c) 2002 JSON.org Permission is hereby granted, free of charge, to any person obtaining a copy of
5    * this software and associated documentation files (the "Software"), to deal in the Software without restriction,
6    * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7    * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
8    * conditions: The above copyright notice and this permission notice shall be included in all copies or substantial
9    * portions of the Software. The Software shall be used for Good, not Evil. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT
10    * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
11    * A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12    * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
13    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14    */
15   
16    import java.util.Arrays;
17    import java.util.LinkedList;
18    import java.util.List;
19   
20    /**
21    * String manipulation methods.
22    */
 
23    class StringUtil
24    {
25    /**
26    * Splits a comma separated list of values. Values must be quoted and can be encased in square-brackets (JSON
27    * style).
28    *
29    * @param the
30    * source String
31    * @return an array of String values
32    */
 
33  12 toggle static String[] split(String source)
34    {
35  12 Null.not("source", source);
36   
37  12 final List result = new JSONList(source.trim());
38  11 return (String[]) result.toArray(new String[result.size()]);
39    }
40   
 
41  65 toggle static String toString(String[] source)
42    {
43  65 Null.not("source", source);
44   
45  65 return new JSONList(source).toString();
46    }
47   
48    /**
49    * subset of JSONArray that simply takes a String and converts to a list.
50    */
 
51    private static class JSONList extends LinkedList
52    {
53    private static final long serialVersionUID = -8317241062936626298L;
54   
 
55  12 toggle JSONList(String source)
56    {
57  12 final Tokenizer tokenizer = new Tokenizer(source);
58   
59  12 if (tokenizer.nextClean() != '[')
60    {
61  1 tokenizer.syntaxError("String must start with square bracket");
62    }
63  11 switch (tokenizer.nextClean())
64    {
65  1 case ']':
66  1 case 0:
67  2 return;
68    }
69  9 tokenizer.back();
70  9 for (;;)
71    {
72  25 if (tokenizer.nextClean() == ',')
73    {
74  2 tokenizer.back();
75  2 this.add(null);
76    }
77    else
78    {
79  23 tokenizer.back();
80  23 this.add(tokenizer.nextValue());
81    }
82  25 final char nextClean = tokenizer.nextClean();
83  25 switch (nextClean)
84    {
85  0 case ';':
86  18 case ',':
87  18 switch (tokenizer.nextClean())
88    {
89  1 case ']':
90  1 case 0:
91  2 return;
92    }
93  16 tokenizer.back();
94  16 break;
95  6 case ']':
96  1 case 0:
97  7 return;
98  0 default:
99  0 tokenizer.syntaxError("Expected a ',' or ']' rather than: " + (int) nextClean);
100    }
101    }
102    }
103   
 
104  65 toggle JSONList(String[] source)
105    {
106  65 super(Arrays.asList(source));
107    }
108   
 
109  65 toggle String join(String separator)
110    {
111  65 final int len = size();
112  65 final StringBuffer sb = new StringBuffer();
113   
114  150 for (int i = 0; i < len; i += 1)
115    {
116  85 if (i > 0)
117    {
118  29 sb.append(separator);
119    }
120  85 sb.append(quote((String) this.get(i)));
121    }
122  65 return sb.toString();
123    }
124   
125    /**
126    * Produce a string in double quotes with backslash sequences in all the right places. A backslash will be
127    * inserted within </, allowing JSON text to be delivered in HTML. In JSON text, a string cannot contain a
128    * control character or an unescaped quote or backslash.
129    *
130    * @param string
131    * A String
132    * @return A String correctly formatted for insertion in a JSON text.
133    */
 
134  85 toggle String quote(String string)
135    {
136  85 if ((string == null) || (string.length() == 0))
137    {
138  0 return "\"\"";
139    }
140   
141  85 char b;
142  85 char c = 0;
143  85 int i;
144  85 final int len = string.length();
145  85 final StringBuffer sb = new StringBuffer(len + 4);
146  85 String t;
147   
148  85 sb.append('"');
149  1265 for (i = 0; i < len; i += 1)
150    {
151  1180 b = c;
152  1180 c = string.charAt(i);
153  1180 switch (c)
154    {
155  0 case '\\':
156  4 case '"':
157  4 sb.append('\\');
158  4 sb.append(c);
159  4 break;
160  24 case '/':
161  24 if (b == '<')
162    {
163  0 sb.append('\\');
164    }
165  24 sb.append(c);
166  24 break;
167  0 case '\b':
168  0 sb.append("\\b");
169  0 break;
170  2 case '\t':
171  2 sb.append("\\t");
172  2 break;
173  0 case '\n':
174  0 sb.append("\\n");
175  0 break;
176  0 case '\f':
177  0 sb.append("\\f");
178  0 break;
179  0 case '\r':
180  0 sb.append("\\r");
181  0 break;
182  1150 default:
183  1150 if ((c < ' ') || ((c >= '\u0080') && (c < '\u00a0')) || ((c >= '\u2000') && (c < '\u2100')))
184    {
185  0 t = "000" + Integer.toHexString(c);
186  0 sb.append("\\u").append(t.substring(t.length() - 4));
187    }
188    else
189    {
190  1150 sb.append(c);
191    }
192    }
193    }
194  85 sb.append('"');
195  85 return sb.toString();
196    }
197   
 
198  65 toggle public String toString()
199    {
200  65 try
201    {
202  65 return '[' + join(",") + ']';
203    }
204    catch (final Exception e)
205    {
206  0 return "";
207    }
208    }
209    /**
210    * Tokenizer takes a source string and extracts characters and tokens from it. Adapted from JSONTokener in the
211    * json.org package.
212    * <p>
213    * Kept as an inner class - or rather ghetto - so outer class can deal with Iterator conversion. Not the
214    * prettiest code in the world by a long shot.
215    */
 
216    private static class Tokenizer
217    {
218    /**
219    * The source string being tokenized.
220    */
221    private final String source;
222   
223    /**
224    * The index of the next character.
225    */
226    private int index = 0;
227   
228    /**
229    * Construct a JSONTokener from a string.
230    *
231    * @param s
232    * A source string.
233    */
 
234  12 toggle Tokenizer(String s)
235    {
236  12 source = s;
237    }
238   
239    /**
240    * Back up one character. This provides a sort of lookahead capability, so that you can test for a digit or
241    * letter before attempting to parse the next number or identifier.
242    */
 
243  50 toggle private void back()
244    {
245  50 if (index > 0)
246    {
247  50 index -= 1;
248    }
249    }
250   
251    /**
252    * Determine if the source string still contains characters that next() can consume.
253    *
254    * @return true if not yet at the end of the source.
255    */
 
256  250 toggle private boolean more()
257    {
258  250 return index < source.length();
259    }
260   
261    /**
262    * Get the next character in the source string.
263    *
264    * @return The next character, or 0 if past the end of the source string.
265    */
 
266  250 toggle private char next()
267    {
268  250 if (more())
269    {
270  247 final char c = source.charAt(index);
271  247 index += 1;
272  247 return c;
273    }
274  3 return 0;
275    }
276   
277    /**
278    * Get the next n characters.
279    *
280    * @param n
281    * The number of characters to take.
282    * @return A string of n characters.
283    * @throws JSONException
284    * Substring bounds error if there are not n characters remaining in the source string.
285    */
 
286  0 toggle private String next(int n)
287    {
288  0 final int i = index;
289  0 final int j = i + n;
290  0 if (j >= source.length())
291    {
292  0 throw new IllegalStateException("Substring bounds error");
293    }
294  0 index += n;
295  0 return source.substring(i, j);
296    }
297   
298    /**
299    * Get the next char in the string, skipping whitespace and comments (slashslash, slashstar, and hash).
300    *
301    * @return A character, or 0 if there are no more characters.
302    * @throws JSONException
303    * in case of a syntax error
304    */
 
305  114 toggle private char nextClean()
306    {
307  114 for (;;)
308    {
309  121 char c = next();
310  121 if (c == '/')
311    {
312  0 switch (next())
313    {
314  0 case '/':
315  0 do
316    {
317  0 c = next();
318    }
319  0 while ((c != '\n') && (c != '\r') && (c != 0));
320  0 break;
321  0 case '*':
322  0 for (;;)
323    {
324  0 c = next();
325  0 if (c == 0)
326    {
327  0 throw new IllegalStateException("Unclosed comment");
328    }
329  0 if (c == '*')
330    {
331  0 if (next() == '/')
332    {
333  0 break;
334    }
335  0 back();
336    }
337    }
338  0 break;
339  0 default:
340  0 back();
341  0 return '/';
342    }
343    }
344  121 else if (c == '#')
345    {
346  0 do
347    {
348  0 c = next();
349    }
350  0 while ((c != '\n') && (c != '\r') && (c != 0));
351    }
352  121 else if ((c == 0) || (c > ' '))
353    {
354  114 return c;
355    }
356    }
357    }
358   
359    /**
360    * Return the characters up to the next close quote character. Backslash processing is done. The formal JSON
361    * format does not allow strings in single quotes, but an implementation is allowed to accept them.
362    *
363    * @param quote
364    * The quoting character, either <code>"</code>&nbsp;<small>(double quote)</small> or
365    * <code>'</code>&nbsp;<small>(single quote)</small>.
366    * @return A String.
367    * @throws JSONException
368    * Unterminated string.
369    */
 
370  23 toggle private String nextString(char quote)
371    {
372  23 char c;
373  23 final StringBuffer sb = new StringBuffer();
374  23 for (;;)
375    {
376  127 c = next();
377  127 switch (c)
378    {
379  0 case 0:
380  0 case '\n':
381  0 case '\r':
382  0 throw new IllegalStateException("Unterminated string");
383  2 case '\\':
384  2 c = next();
385  2 switch (c)
386    {
387  0 case 'b':
388  0 sb.append('\b');
389  0 break;
390  1 case 't':
391  1 sb.append('\t');
392  1 break;
393  0 case 'n':
394  0 sb.append('\n');
395  0 break;
396  0 case 'f':
397  0 sb.append('\f');
398  0 break;
399  0 case 'r':
400  0 sb.append('\r');
401  0 break;
402  0 case 'u':
403  0 sb.append((char) Integer.parseInt(next(4), 16));
404  0 break;
405  0 case 'x':
406  0 sb.append((char) Integer.parseInt(next(2), 16));
407  0 break;
408  1 default:
409  1 sb.append(c);
410    }
411  2 break;
412  125 default:
413  125 if (c == quote)
414    {
415  23 return sb.toString();
416    }
417  102 sb.append(c);
418    }
419    }
420    }
421   
422    /**
423    * Get the next value. The value can be a Boolean, Double, Integer, JSONArray, JSONObject, Long, or String,
424    * or the JSONObject.NULL object.
425    *
426    * @return An object.
427    * @throws JSONException
428    * If syntax error.
429    */
 
430  23 toggle private String nextValue()
431    {
432  23 char c = nextClean();
433  23 String s;
434   
435  23 switch (c)
436    {
437  23 case '"':
438  0 case '\'':
439  23 return nextString(c);
440    }
441   
442    /*
443    * Handle unquoted text. This could be the values true, false, or null, or it can be a number. An
444    * implementation (such as this one) is allowed to also accept non-standard forms. Accumulate characters
445    * until we reach the end of the text or a formatting character.
446    */
447   
448  0 final StringBuffer sb = new StringBuffer();
449  0 while ((c >= ' ') && (",:]}/\\\"[{;=#".indexOf(c) <= 0))
450    {
451  0 sb.append(c);
452  0 c = next();
453    }
454  0 back();
455   
456    /*
457    * If it is true, false, or null, return the proper value.
458    */
459   
460  0 s = sb.toString().trim();
461  0 if (s.equals(""))
462    {
463  0 throw new IllegalStateException("Missing value" + toString());
464    }
465  0 if (s.equalsIgnoreCase("null"))
466    {
467  0 return null;
468    }
469   
470  0 return s;
471    }
472   
 
473  1 toggle void syntaxError(String message)
474    {
475  1 throw new IllegalStateException(message + toString());
476    }
477   
 
478  1 toggle public String toString()
479    {
480  1 return " at character " + index + " of " + source;
481    }
482    }
483    }
484    }