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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1783 - (hide 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 iliev 596 /*
2     * jlscp - a java LinuxSampler control protocol API
3     *
4 iliev 1728 * Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com>
5 iliev 596 *
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 iliev 1346 public final class Parser {
35 iliev 1139 /** Forbits the instantiatrion of this class */
36     private Parser() { }
37    
38 iliev 596 /**
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 iliev 1491 public static String[]
71 iliev 1139 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 iliev 1491 public static String[]
80 iliev 1139 parseList(String list, char separator) {
81 iliev 596 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 iliev 1139 while((idx = list.indexOf(separator, pos)) > 0) {
86 iliev 596 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 iliev 1491 public static Boolean[]
101 iliev 596 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 iliev 1491 public static Integer[]
121 iliev 1139 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 iliev 1491 public static Integer[]
133 iliev 1139 parseIntList(String list, char separator) throws LscpException {
134     String[] ar = parseList(list, separator);
135 iliev 596
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 iliev 1491 public static Float[]
151 iliev 596 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 iliev 1326
160 iliev 596 /**
161 iliev 1346 * 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 iliev 1491 public static String[]
166 iliev 1346 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 iliev 1491 public static String[]
177 iliev 1346 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 iliev 1326 * 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 iliev 1491 public static String[]
217 iliev 1393 parseStringList(String list) throws LscpException {
218     return parseStringList(list, ',');
219 iliev 1326 }
220    
221     /**
222 iliev 1202 * 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 iliev 1491 public static String[]
229 iliev 1393 parseStringList(String list, char separator) throws LscpException {
230 iliev 596 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 iliev 1202 if(list.charAt(q2 + 1) != separator)
244 iliev 596 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 iliev 1393 s2S[0] = parseStringList(list);
261 iliev 596 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 iliev 1393 for(i = 0; i < v.size(); i++) s2S[i] = parseStringList(v.get(i));
278 iliev 596
279     return s2S;
280     }
281    
282 iliev 1139 /**
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 iliev 1491 public static String[]
291 iliev 1139 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 iliev 596 /** 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 iliev 784
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 iliev 1491 public static String
508 iliev 784 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 iliev 1307
518     /**
519     * Returns the provided string with added escape sequences where necessary.
520     */
521 iliev 1346 public static String
522     toEscapedString(Object obj) {
523     String s = obj.toString();
524 iliev 1307 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 iliev 1346
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 iliev 1351 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 iliev 1346 default : sb.append(s.charAt(i));
561     }
562     }
563    
564     return sb.toString();
565     }
566    
567     /**
568 iliev 1728 * 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 iliev 1783 else if(c < ' ' || c > '~') sb.append(toEscapeString(c));
579 iliev 1728 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 iliev 1783 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 iliev 1728 /**
605 iliev 1346 * 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 iliev 1351 return toNonEscapedString(obj);
611 iliev 1346 }
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 iliev 1351 toNonEscapedString(Object obj) {
619 iliev 1346 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 iliev 1351 Client.getLogger().info("Broken escape sequence!");
626 iliev 1346 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 iliev 1351 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 iliev 1346 } else {
647     sb.append(c);
648     }
649     }
650    
651     return sb.toString();
652     }
653    
654 iliev 1351 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 iliev 1346 /**
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 iliev 1491 public static boolean
750 iliev 1346 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 iliev 1491 public static String
764 iliev 1346 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 iliev 596 }

  ViewVC Help
Powered by ViewVC