/[svn]/jlscp/trunk/src/org/linuxsampler/lscp/Parser.java
ViewVC logotype

Contents of /jlscp/trunk/src/org/linuxsampler/lscp/Parser.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1783 - (show annotations) (download)
Tue Sep 30 03:17:26 2008 UTC (15 years, 6 months ago) by iliev
File size: 25068 byte(s)
* Added support for escaping unicode characters

1 /*
2 * jlscp - a java LinuxSampler control protocol API
3 *
4 * Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com>
5 *
6 * This file is part of jlscp.
7 *
8 * jlscp is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * jlscp is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with jlscp; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23 package org.linuxsampler.lscp;
24
25 import java.io.IOException;
26
27 import java.util.Vector;
28
29
30 /**
31 * This class contains only helper functions that are used from the other classes in this library.
32 * @author Grigor Iliev
33 */
34 public final class Parser {
35 /** Forbits the instantiatrion of this class */
36 private Parser() { }
37
38 /**
39 * Parses an integer value.
40 * @param s The integer value to be parsed.
41 * @throws LscpException If the string does not contain valid integer value.
42 */
43 protected static int
44 parseInt(String s) throws LscpException {
45 try { return Integer.parseInt(s); }
46 catch(NumberFormatException x) {
47 throw new LscpException(LscpI18n.getLogMsg("Parser.notInt!", s), x);
48 }
49 }
50
51 /**
52 * Parses a float value.
53 * @param s The float value to be parsed.
54 * @throws LscpException If the string does not contain valid float value.
55 */
56 protected static float
57 parseFloat(String s) throws LscpException {
58 try { return Float.parseFloat(s); }
59 catch(NumberFormatException x) {
60 throw new LscpException(LscpI18n.getLogMsg("Parser.notFloat!", s));
61 }
62 }
63
64 /**
65 * Parses a comma separated list.
66 *
67 * @param list The comma separated list.
68 * @return A <code>String</code> array containing all items in the list.
69 */
70 public static String[]
71 parseList(String list) { return parseList(list, ','); }
72
73 /**
74 * Parses a list.
75 * @param list The list to parse.
76 * @param separator Provides the character used as separator.
77 * @return A <code>String</code> array containing all items in the list.
78 */
79 public static String[]
80 parseList(String list, char separator) {
81 if(list == null || list.length() == 0) return new String[0];
82 int pos = 0;
83 int idx;
84 Vector<String> v = new Vector<String>();
85 while((idx = list.indexOf(separator, pos)) > 0) {
86 v.add(list.substring(pos, idx));
87 pos = idx + 1;
88 }
89
90 if(pos < list.length()) v.add(list.substring(pos));
91 return v.toArray(new String[v.size()]);
92 }
93
94 /**
95 * Parses a comma separated list with boolean values.
96 *
97 * @param list The comma separated list with boolean values.
98 * @return A <code>Boolean</code> array containing all items in the list.
99 */
100 public static Boolean[]
101 parseBoolList(String list) {
102 String[] ar = parseList(list);
103
104 Boolean[] bar = new Boolean[ar.length];
105 for(int i = 0; i < ar.length; i++) {
106 bar[i] = Boolean.parseBoolean(ar[i]);
107 }
108
109 return bar;
110 }
111
112 /**
113 * Parses a comma separated list with integer values.
114 *
115 * @param list The comma separated list with integer values.
116 * @return A <code>Integer</code> array containing all items in the list.
117 *
118 * @throws LscpException if the list contains value(s) from different type.
119 */
120 public static Integer[]
121 parseIntList(String list) throws LscpException { return parseIntList(list, ','); }
122
123 /**
124 * Parses a list of integer values.
125 *
126 * @param list The list of integer values.
127 * @param separator Provides the character used as separator.
128 * @return A <code>Integer</code> array containing all items in the list.
129 *
130 * @throws LscpException if the list contains value(s) from different type.
131 */
132 public static Integer[]
133 parseIntList(String list, char separator) throws LscpException {
134 String[] ar = parseList(list, separator);
135
136 Integer[] iar = new Integer[ar.length];
137 for(int i = 0; i < ar.length; i++) iar[i] = parseInt(ar[i]);
138
139 return iar;
140 }
141
142 /**
143 * Parses a comma separated list with float values.
144 *
145 * @param list The comma separated list with float values.
146 * @return A <code>Float</code> array containing all items in the list.
147 *
148 * @throws LscpException if the list contains value(s) from different type.
149 */
150 public static Float[]
151 parseFloatList(String list) throws LscpException {
152 String[] ar = parseList(list);
153
154 Float[] far = new Float[ar.length];
155 for(int i = 0; i < ar.length; i++) far[i] = parseFloat(ar[i]);
156
157 return far;
158 }
159
160 /**
161 * Parses a comma separated string list, which elements contains escaped sequences.
162 * @param list The list to parse.
163 * @return A <code>String</code> array containing all items in the list.
164 */
165 public static String[]
166 parseEscapedStringList(String list) throws LscpException {
167 return parseEscapedStringList(list, ',');
168 }
169
170 /**
171 * Parses a string list, which elements contains escaped sequences.
172 * @param list The list to parse.
173 * @param separator Provides the character used as separator.
174 * @return A <code>String</code> array containing all items in the list.
175 */
176 public static String[]
177 parseEscapedStringList(String list, char separator) throws LscpException {
178 if(list == null || list.length() == 0) return new String[0];
179 int q1 = 0, q2 = 0;
180 Vector<String> v = new Vector<String>();
181
182 for(;;) {
183 if(list.charAt(q1) != '\'')
184 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
185 q2 = findApostrophe(list, q1 + 1);
186 if(q2 == -1) throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
187 v.add(list.substring(q1 + 1, q2));
188
189 if(q2 + 1 >= list.length()) break;
190
191 if(list.charAt(q2 + 1) != separator)
192 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
193 q1 = q2 + 2;
194 if(q1 >= list.length())
195 throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
196 }
197
198 return v.toArray(new String[v.size()]);
199 }
200
201 /**
202 * Returns the index of the first occurrence of a non-escaped apostrophe
203 * in the specified string, starting at <b>index</b>, or -1 if nothing is found.
204 */
205 private static int
206 findApostrophe(String s, int index) {
207 return findNonEscapedChar(s, index, '\'');
208 }
209
210 /**
211 * Parses a comma separated list whose items are encapsulated into apostrophes.
212 * @param list The comma separated list.
213 * @return A <code>String</code> array containing all items in the list.
214 * @throws LscpException if the list is broken.
215 */
216 public static String[]
217 parseStringList(String list) throws LscpException {
218 return parseStringList(list, ',');
219 }
220
221 /**
222 * Parses a list whose items are encapsulated into apostrophes.
223 * @param list The list of strings.
224 * @param separator Provides the character used as separator.
225 * @return A <code>String</code> array containing all items in the list.
226 * @throws LscpException if the list is broken.
227 */
228 public static String[]
229 parseStringList(String list, char separator) throws LscpException {
230 if(list == null || list.length() == 0) return new String[0];
231 int q1 = 0, q2 = 0;
232 Vector<String> v = new Vector<String>();
233
234 for(;;) {
235 if(list.charAt(q1) != '\'')
236 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
237 q2 = list.indexOf('\'', q1 + 1);
238 if(q2 == -1) throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
239 v.add(list.substring(q1 + 1, q2));
240
241 if(q2 + 1 >= list.length()) break;
242
243 if(list.charAt(q2 + 1) != separator)
244 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
245 q1 = q2 + 2;
246 if(q1 >= list.length())
247 throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
248 }
249
250 return v.toArray(new String[v.size()]);
251 }
252
253 protected static String[][]
254 parseListOfStringLists(String list) throws LscpException {
255 if(list.length() == 0) return new String[0][0];
256
257 String[][] s2S;
258 if(!list.startsWith("''") && !list.startsWith("\"\"")) {
259 s2S = new String[1][];
260 s2S[0] = parseStringList(list);
261 return s2S;
262 }
263
264 int i = 0, i2 = 0;
265 Vector<String> v = new Vector<String>();
266
267 for(;;) {
268 i2 = getEndListIndex(i, list);
269 v.add(list.substring(i + 1, i2));
270 if(i2 == list.length() - 1) break;
271 if(list.charAt(i2 + 1) != ',')
272 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
273 i = i2 + 2;
274 }
275
276 s2S = new String[v.size()][];
277 for(i = 0; i < v.size(); i++) s2S[i] = parseStringList(v.get(i));
278
279 return s2S;
280 }
281
282 /**
283 * Parses a comma separated list whose items are encapsulated into curly braces.
284 *
285 * @param list The comma separated list.
286 * @return A <code>String</code> array containing all items in the list.
287 *
288 * @throws LscpException if the list is broken.
289 */
290 public static String[]
291 parseArray(String list) throws LscpException {
292 if(list == null || list.length() == 0) return new String[0];
293 int q1 = 0, q2 = 0;
294 Vector<String> v = new Vector<String>();
295
296 for(;;) {
297 if(list.charAt(q1) != '{')
298 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
299 q2 = list.indexOf('}', q1 + 1);
300 if(q2 == -1) throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
301 v.add(list.substring(q1 + 1, q2));
302
303 if(q2 + 1 >= list.length()) break;
304
305 if(list.charAt(q2 + 1) != ',')
306 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
307 q1 = q2 + 2;
308 if(q1 >= list.length())
309 throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
310 }
311
312 return v.toArray(new String[v.size()]);
313 }
314
315 /** Helper function used by <code>parseListOfStringLists</code>. */
316 private static int
317 getEndListIndex(int start, String list) throws LscpException {
318 int i = start + 1;
319 char q = list.charAt(0); // quote symbol
320 if(list.charAt(start) != q)
321 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
322
323 if(list.charAt(i) == '\'') { // Check for empty list
324 if(i == list.length() - 1 || list.charAt(i + 1) == ',') return i;
325 }
326
327 for(;;) {
328 if(list.charAt(i) != q)
329 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
330 i = list.indexOf(q, i + 1);
331 if(i == -1 || i == list.length() - 1)
332 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
333
334 if(list.charAt(i + 1) == q) return i + 1;
335
336 if(list.charAt(i + 1) != ',')
337 throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
338 i += 2;
339 }
340 }
341
342
343 /**
344 * Gets the type of the parameter represented by the specified result set.
345 * @param resultSet A <code>String</code> array containing the information categories
346 * of a multi-line result set.
347 * @return The type of the parameter represented by the specified result set or
348 * <code>null</code> if the specified result set does not contain
349 * <code>TYPE</code> category.
350 */
351 protected static ParameterType
352 parseType(String[] resultSet) {
353 if(resultSet == null || resultSet.length == 0) return null;
354 for(String s : resultSet) {
355 if(s.startsWith("TYPE: ")) {
356 String type = s.substring("TYPE: ".length(), s.length());
357 if(type.equals("BOOL")) return ParameterType.BOOL;
358 if(type.equals("INT")) return ParameterType.INT;
359 if(type.equals("FOAT")) return ParameterType.FLOAT;
360 if(type.equals("STRING")) return ParameterType.STRING;
361 }
362 }
363 return null;
364 }
365
366 /**
367 * Determines whether the parameter represented by the specified result set allows
368 * only one value or a list of values.
369 * @param resultSet A <code>String</code> array containing the information categories
370 * of a multi-line result set.
371 * @return <code>false</code> if the parameter represented by the specified result set
372 * allows only one value and <code>true</code> if allows a list of values.
373 */
374 protected static Boolean
375 parseMultiplicity(String[] resultSet) {
376 if(resultSet == null || resultSet.length == 0) return null;
377
378 for(String s : resultSet) {
379 if(s.startsWith("MULTIPLICITY: ")) return Boolean.parseBoolean (
380 s.substring("MULTIPLICITY: ".length(), s.length())
381 );
382 }
383
384 return null;
385 }
386
387 /**
388 * Parses an empty result set and returns an appropriate <code>ResultSet</code> object.
389 * Notice that the result set may be of type warning or error.
390 * @param ln A <code>String</code> representing the single line result set to be parsed.
391 * @return A <code>ResultSet</code> object.
392 * @throws LscpException If LSCP protocol error occurs.
393 * @throws LSException If the LinuxSampler instance returns error message.
394 */
395 protected static ResultSet
396 parseEmptyResultSet(String ln) throws LscpException, LSException {
397 ResultSet rs = new ResultSet();
398
399 if(ln.equals("OK")) {
400 return rs;
401 } else if(ln.startsWith("OK[") && ln.endsWith("]")) {
402 ln = ln.substring("OK[".length(), ln.length() - 1);
403 try {
404 rs.setIndex(Integer.parseInt(ln));
405 return rs;
406 } catch(NumberFormatException x) {
407 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
408 }
409 } else if(ln.startsWith("WRN")) {
410 parseWarning(ln, rs);
411 Client.getLogger().warning(rs.getMessage());
412 return rs;
413 } else if(ln.startsWith("ERR:")) {
414 parseError(ln, rs);
415 throw new LSException(rs.getCode(), rs.getMessage());
416 }
417
418 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!") );
419 }
420
421 /**
422 * Parses warning message.
423 * @param ln The warning message to be parsed.
424 * @param rs A <code>ResultSet</code> instance where the warning must be stored.
425 * @throws LscpException If LSCP protocol corruption occurs.
426 */
427 protected static void
428 parseWarning(String ln, ResultSet rs) throws LscpException {
429 if(!ln.startsWith("WRN"))
430 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
431
432 int i, j;
433 rs.setWarning(true);
434
435 if(ln.charAt(3) == '[') {
436 i = ln.indexOf(']');
437 if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
438
439 try {
440 j = Integer.parseInt(ln.substring("WRN[".length(), i));
441 rs.setIndex(j);
442 } catch(NumberFormatException x) {
443 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
444 }
445
446 if(ln.charAt(i + 1) != ':')
447 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
448 }
449
450 i = ln.indexOf(':');
451 if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
452 j = ln.indexOf(':', i + 1);
453 if(j == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
454
455 try { rs.setCode(Integer.parseInt(ln.substring(i + 1, j))); }
456 catch(NumberFormatException x) {
457 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
458 }
459
460 rs.setMessage(ln.substring(j + 1));
461 }
462
463 /**
464 * Parses error message.
465 * @param ln The error message to be parsed.
466 * @param rs A <code>ResultSet</code> instance where the error must be stored.
467 * @throws LscpException If LSCP protocol corruption occurs.
468 */
469 protected static void
470 parseError(String ln, ResultSet rs) throws LscpException {
471 if(!ln.startsWith("ERR:"))
472 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
473
474 int i = ln.indexOf(':', "ERR:".length());
475 if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
476
477 try { rs.setCode(Integer.parseInt(ln.substring("ERR:".length(), i))); }
478 catch(NumberFormatException x) {
479 throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
480 }
481
482 rs.setMessage(ln.substring(i + 1));
483 }
484
485 /**
486 * Gets the info character string to the specified information category.
487 * @param resultSet A <code>String</code> array containing the information categories
488 * of a multi-line result set.
489 * @param category Specifies the category whose info character string to be returned.
490 * @return The info character string to the specified information category or
491 * <code>null</code> if the specified result set does not contain that category.
492 */
493 protected static String
494 getCategoryInfo(String[] resultSet, String category) {
495 String c = category + ": ";
496 for(String s : resultSet)
497 if(s.startsWith(c)) return s.substring(c.length(), s.length());
498
499 return null;
500 }
501
502 /**
503 * Eliminates the quotation marks if the string is quoted.
504 * @return New string without quotation marks if the string is quoted; else
505 * the same string is returned.
506 */
507 public static String
508 removeQuotation(String s) {
509 if(s == null || s.length() < 2) return s;
510 char q = s.charAt(0);
511 char q2 = s.charAt(s.length() - 1);
512 if((q == '\'' && q2 == '\'') || (q == '"' && q2 == '"'))
513 return s.substring(1, s.length() - 1);
514
515 return s;
516 }
517
518 /**
519 * Returns the provided string with added escape sequences where necessary.
520 */
521 public static String
522 toEscapedString(Object obj) {
523 String s = obj.toString();
524 StringBuffer sb = new StringBuffer();
525 for(int i = 0; i < s.length(); i++) {
526 switch(s.charAt(i)) {
527 case '\n': sb.append("\\n"); break;
528 case '\r': sb.append("\\r"); break;
529 case '\f': sb.append("\\f"); break;
530 case '\t': sb.append("\\t"); break;
531 case 0x0B: sb.append("\\v"); break;
532 case '\'': sb.append("\\'"); break;
533 case '\"': sb.append("\\\""); break;
534 case '\\': sb.append("\\\\"); break;
535 default : sb.append(s.charAt(i));
536 }
537 }
538
539 return sb.toString();
540 }
541
542 /**
543 * Returns the provided file name with added escape sequences where necessary.
544 */
545 public static String
546 toEscapedFileName(Object obj) {
547 String s = obj.toString();
548 StringBuffer sb = new StringBuffer();
549 for(int i = 0; i < s.length(); i++) {
550 switch(s.charAt(i)) {
551 case '/' : sb.append("\\x2f"); break;
552 case '\n': sb.append("\\n"); break;
553 case '\r': sb.append("\\r"); break;
554 case '\f': sb.append("\\f"); break;
555 case '\t': sb.append("\\t"); break;
556 case 0x0B: sb.append("\\v"); break;
557 case '\'': sb.append("\\'"); break;
558 case '\"': sb.append("\\\""); break;
559 case '\\': sb.append("\\\\"); break;
560 default : sb.append(s.charAt(i));
561 }
562 }
563
564 return sb.toString();
565 }
566
567 /**
568 * Returns more aggressively escaped sequence of the provided escaped string.
569 * @param escapedString Already escaped string, which should be escaped more aggressively.
570 */
571 public static String
572 toExtendedEscapeSequence(String escapedString) {
573 StringBuffer sb = new StringBuffer();
574 for(int i = 0; i < escapedString.length(); i++) {
575 char c = escapedString.charAt(i);
576
577 if(c == '`') sb.append("\\x60");
578 else if(c < ' ' || c > '~') sb.append(toEscapeString(c));
579 else sb.append(c);
580 /*if(c == '/' || c == '\\' || c == '\'' || c == '"') sb.append(c);
581 else if(c >= '0' && c <='9') sb.append(c);
582 else if((c >= 'A' && c <='Z') || (c >= 'a' && c <='z')) sb.append(c);
583 else {
584
585 }*/
586 }
587
588 return sb.toString();
589 }
590
591 private static String
592 toEscapeString(char c) {
593 String s = Integer.toHexString((int)c);
594 if(s.length() % 2 != 0) s = "0" + s;
595 StringBuffer sb = new StringBuffer();
596 for(int i = 0; i < s.length();) {
597 sb.append("\\x").append(s.charAt(i)).append(s.charAt(i + 1));
598 i += 2;
599 }
600
601 return sb.toString();
602 }
603
604 /**
605 * Removes the escape sequences from the specified file name
606 * @return The provided file name with removed escape sequences.
607 */
608 public static String
609 toNonEscapedFileName(Object obj) {
610 return toNonEscapedString(obj);
611 }
612
613 /**
614 * Removes the escape sequences from the string <code>obj.toString()</code>.
615 * @return The provided text with removed escape sequences.
616 */
617 public static String
618 toNonEscapedString(Object obj) {
619 String s = obj.toString();
620 StringBuffer sb = new StringBuffer();
621 for(int i = 0; i < s.length(); i++) {
622 char c = s.charAt(i);
623 if(c == '\\') {
624 if(i >= s.length()) {
625 Client.getLogger().info("Broken escape sequence!");
626 break;
627 }
628 char c2 = s.charAt(++i);
629 if(c2 == '\'') sb.append('\'');
630 else if(c2 == '"') sb.append('"');
631 else if(c2 == '\\') sb.append('\\');
632 else if(c2 == 'r') sb.append('\r');
633 else if(c2 == 'n') sb.append('\n');
634 else if(c2 == 'f') sb.append('\f');
635 else if(c2 == 't') sb.append('\t');
636 else if(c2 == 'v') sb.append((char)0x0B);
637 else if(c2 == 'x') {
638 Character ch = getHexEscapeSequence(s, i + 1);
639 if(ch != null) sb.append(ch.charValue());
640 i += 2;
641 } else if(c2 >= '0' && c2 <= '9') {
642 Character ch = getOctEscapeSequence(s, i);
643 if(ch != null) sb.append(ch.charValue());
644 i += 2;
645 } else Client.getLogger().info("Unknown escape sequence \\" + c2);
646 } else {
647 sb.append(c);
648 }
649 }
650
651 return sb.toString();
652 }
653
654 private static Character
655 getHexEscapeSequence(String s, int index) {
656 Character c = null;
657
658 if(index + 1 >= s.length()) {
659 Client.getLogger().info("Broken escape sequence");
660 return c;
661 }
662
663 try { c = (char)Integer.parseInt(s.substring(index, index + 2), 16); }
664 catch(Exception x) { Client.getLogger().info("Broken escape sequence!"); }
665
666 return c;
667 }
668
669 private static Character
670 getOctEscapeSequence(String s, int index) {
671 Character c = null;
672
673 if(index + 2 >= s.length()) {
674 Client.getLogger().info("Broken escape sequence");
675 return c;
676 }
677
678 try { c = (char)Integer.parseInt(s.substring(index, index + 3), 8); }
679 catch(Exception x) { Client.getLogger().info("Broken escape sequence!"); }
680
681 return c;
682 }
683
684 /**
685 * Determines whether the character at the specified position
686 * is escaped with backslash.
687 */
688 public static boolean
689 isEscaped(String s, int index) {
690 if (index < 0 || index >= s.length()) return false;
691 int count = 0;
692 for (int i = index - 1; i >= 0; i--) {
693 if (s.charAt(i) != '\\') break;
694 count++;
695 }
696 return count % 2 != 0;
697 }
698
699 /**
700 * Returns the index of the first occurrence of the specified non-escaped character
701 * in the specified string, starting at <b>index</b>, or -1 if nothing is found.
702 */
703 private static int
704 findNonEscapedChar(String s, int index, char c) {
705 if(s == null) return -1;
706 int pos = index;
707 if (pos < 0 || pos >= s.length()) return -1;
708
709 for(;;) {
710 int i = s.indexOf(c, pos);
711 if (i == -1) break;
712 if (!isEscaped(s, i)) return i;
713 pos = i + 1;
714 if (pos >= s.length()) break;
715 }
716
717 return -1;
718 }
719
720 /**
721 * Returns the index of the first occurrence of a file separator
722 * in the specified escaped path, starting at <b>index</b>, or -1 if nothing is found.
723 */
724 private static int
725 findFileSeparator(String path, int index) {
726 return findNonEscapedChar(path, index, '/');
727 }
728
729 /**
730 * Gets the position of the last file separator in the specified
731 * escaped path, or -1 if failed.
732 */
733 private static int
734 getLastFileSeparator(String path) {
735 if(path == null || path.length() == 0) return -1;
736 int pos = path.length() - 1;
737
738 for(;;) {
739 pos = path.lastIndexOf('/', pos);
740 if(pos == -1) return -1;
741 if(!isEscaped(path, pos)) return pos;
742 pos--;
743 }
744 }
745
746 /**
747 * Determines whether the specified escaped path ends with a file separator.
748 */
749 public static boolean
750 hasEndingFileSeparator(String path) {
751 if(path == null || path.length() < 2) return false;
752
753 int last = path.length() - 1;
754 if(path.charAt(last) == '/' && !isEscaped(path, last)) return true;
755
756 return false;
757 }
758
759 /**
760 * If the specified escaped path ends with a file separator,
761 * a new string is returned with the ending file separator removed.
762 */
763 public static String
764 removeEndingFileSeparator(String path) {
765 if(path == null || path.length() < 2) return path;
766
767 int last = path.length() - 1;
768 if(path.charAt(last) == '/' && !isEscaped(path, last)) {
769 path = path.substring(0, path.length() - 1);
770 }
771
772 return path;
773 }
774
775 /**
776 * Gets the parent directory of the specified escaped path.
777 */
778 public static String
779 getParentDirectory(String path) {
780 if(path == null || path.length() == 0) return null;
781 if(path.charAt(0) != '/') return null;
782 if(path.length() == 1) return null;
783
784 path = removeEndingFileSeparator(path);
785
786 int i = getLastFileSeparator(path);
787 if(i == 0) return "/";
788 return path.substring(0, i);
789 }
790
791 /**
792 * Extracts the file name from the specified escaped path.
793 * If the path does not ends with a file name, <code>null</code> is returned.
794 */
795 public static String
796 getFileName(String path) {
797 if(path == null || path.length() < 2) return null;
798 int i = getLastFileSeparator(path);
799 if(i == -1) return null;
800 if(i == path.length() - 1) return null;
801 return path.substring(i + 1);
802 }
803
804 /**
805 * Returns an array containing all directories in the specified escaped path.
806 */
807 public static String[]
808 getDirectoryList(String path) {
809 if(path == null || path.length() == 0) return null;
810 if(path.charAt(0) != '/') return null;
811 Vector<String> v = new Vector<String>();
812 v.add("/");
813 if(path.length() == 1) return v.toArray(new String[v.size()]);
814
815 if(!hasEndingFileSeparator(path)) path += "/";
816 int i = 1;
817 int j = findFileSeparator(path, i);
818
819 while(j != -1) {
820 v.add(path.substring(i, j));
821
822 i = j + 1;
823 if(i >= path.length()) return v.toArray(new String[v.size()]);
824 j = findFileSeparator(path, i);
825 }
826
827 return null;
828 }
829 }

  ViewVC Help
Powered by ViewVC