/*
* jlscp - a java LinuxSampler control protocol API
*
* Copyright (C) 2005 Grigor Kirilov Iliev
*
* This file is part of jlscp.
*
* jlscp is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* jlscp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with jlscp; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package org.linuxsampler.lscp;
import java.io.IOException;
import java.util.Vector;
/**
* This class contains only helper functions that are used from the other classes in this library.
* @author Grigor Iliev
*/
final class Parser {
/**
* Parses an integer value.
* @param s The integer value to be parsed.
* @throws LscpException If the string does not contain valid integer value.
*/
protected static int
parseInt(String s) throws LscpException {
try { return Integer.parseInt(s); }
catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("Parser.notInt!", s), x);
}
}
/**
* Parses a float value.
* @param s The float value to be parsed.
* @throws LscpException If the string does not contain valid float value.
*/
protected static float
parseFloat(String s) throws LscpException {
try { return Float.parseFloat(s); }
catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("Parser.notFloat!", s));
}
}
/**
* Parses a comma separated list.
*
* @param list The comma separated list.
* @return A String
array containing all items in the list.
*/
protected static String[]
parseList(String list) {
if(list == null || list.length() == 0) return new String[0];
int pos = 0;
int idx;
Vector v = new Vector();
while((idx = list.indexOf(',', pos)) > 0) {
v.add(list.substring(pos, idx));
pos = idx + 1;
}
if(pos < list.length()) v.add(list.substring(pos));
return v.toArray(new String[v.size()]);
}
/**
* Parses a comma separated list with boolean values.
*
* @param list The comma separated list with boolean values.
* @return A Boolean
array containing all items in the list.
*/
protected static Boolean[]
parseBoolList(String list) {
String[] ar = parseList(list);
Boolean[] bar = new Boolean[ar.length];
for(int i = 0; i < ar.length; i++) {
bar[i] = Boolean.parseBoolean(ar[i]);
}
return bar;
}
/**
* Parses a comma separated list with integer values.
*
* @param list The comma separated list with integer values.
* @return A Integer
array containing all items in the list.
*
* @throws LscpException if the list contains value(s) from different type.
*/
protected static Integer[]
parseIntList(String list) throws LscpException {
String[] ar = parseList(list);
Integer[] iar = new Integer[ar.length];
for(int i = 0; i < ar.length; i++) iar[i] = parseInt(ar[i]);
return iar;
}
/**
* Parses a comma separated list with float values.
*
* @param list The comma separated list with float values.
* @return A Float
array containing all items in the list.
*
* @throws LscpException if the list contains value(s) from different type.
*/
protected static Float[]
parseFloatList(String list) throws LscpException {
String[] ar = parseList(list);
Float[] far = new Float[ar.length];
for(int i = 0; i < ar.length; i++) far[i] = parseFloat(ar[i]);
return far;
}
/**
* Parses a comma separated list whose items are encapsulated into apostrophes.
*
* @param list The comma separated list.
* @return A String
array containing all items in the list.
*
* @throws LscpException if the list is broken.
*/
protected static String[]
parseStringList(String list) throws LscpException {
if(list == null || list.length() == 0) return new String[0];
int q1 = 0, q2 = 0;
Vector v = new Vector();
for(;;) {
if(list.charAt(q1) != '\'')
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
q2 = list.indexOf('\'', q1 + 1);
if(q2 == -1) throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
v.add(list.substring(q1 + 1, q2));
if(q2 + 1 >= list.length()) break;
if(list.charAt(q2 + 1) != ',')
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
q1 = q2 + 2;
if(q1 >= list.length())
throw new LscpException(LscpI18n.getLogMsg("Parser.EOL!"));
}
return v.toArray(new String[v.size()]);
}
protected static String[][]
parseListOfStringLists(String list) throws LscpException {
if(list.length() == 0) return new String[0][0];
String[][] s2S;
if(!list.startsWith("''") && !list.startsWith("\"\"")) {
s2S = new String[1][];
s2S[0] = parseStringList(list);
return s2S;
}
int i = 0, i2 = 0;
Vector v = new Vector();
for(;;) {
i2 = getEndListIndex(i, list);
v.add(list.substring(i + 1, i2));
if(i2 == list.length() - 1) break;
if(list.charAt(i2 + 1) != ',')
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
i = i2 + 2;
}
s2S = new String[v.size()][];
for(i = 0; i < v.size(); i++) s2S[i] = Parser.parseStringList(v.get(i));
return s2S;
}
/** Helper function used by parseListOfStringLists
. */
private static int
getEndListIndex(int start, String list) throws LscpException {
int i = start + 1;
char q = list.charAt(0); // quote symbol
if(list.charAt(start) != q)
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
if(list.charAt(i) == '\'') { // Check for empty list
if(i == list.length() - 1 || list.charAt(i + 1) == ',') return i;
}
for(;;) {
if(list.charAt(i) != q)
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
i = list.indexOf(q, i + 1);
if(i == -1 || i == list.length() - 1)
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
if(list.charAt(i + 1) == q) return i + 1;
if(list.charAt(i + 1) != ',')
throw new LscpException(LscpI18n.getLogMsg("Parser.brokenList!"));
i += 2;
}
}
/**
* Gets the type of the parameter represented by the specified result set.
* @param resultSet A String
array containing the information categories
* of a multi-line result set.
* @return The type of the parameter represented by the specified result set or
* null
if the specified result set does not contain
* TYPE
category.
*/
protected static ParameterType
parseType(String[] resultSet) {
if(resultSet == null || resultSet.length == 0) return null;
for(String s : resultSet) {
if(s.startsWith("TYPE: ")) {
String type = s.substring("TYPE: ".length(), s.length());
if(type.equals("BOOL")) return ParameterType.BOOL;
if(type.equals("INT")) return ParameterType.INT;
if(type.equals("FOAT")) return ParameterType.FLOAT;
if(type.equals("STRING")) return ParameterType.STRING;
}
}
return null;
}
/**
* Determines whether the parameter represented by the specified result set allows
* only one value or a list of values.
* @param resultSet A String
array containing the information categories
* of a multi-line result set.
* @return false
if the parameter represented by the specified result set
* allows only one value and true
if allows a list of values.
*/
protected static Boolean
parseMultiplicity(String[] resultSet) {
if(resultSet == null || resultSet.length == 0) return null;
for(String s : resultSet) {
if(s.startsWith("MULTIPLICITY: ")) return Boolean.parseBoolean (
s.substring("MULTIPLICITY: ".length(), s.length())
);
}
return null;
}
/**
* Parses an empty result set and returns an appropriate ResultSet
object.
* Notice that the result set may be of type warning or error.
* @param ln A String
representing the single line result set to be parsed.
* @return A ResultSet
object.
* @throws LscpException If LSCP protocol error occurs.
* @throws LSException If the LinuxSampler instance returns error message.
*/
protected static ResultSet
parseEmptyResultSet(String ln) throws LscpException, LSException {
ResultSet rs = new ResultSet();
if(ln.equals("OK")) {
return rs;
} else if(ln.startsWith("OK[") && ln.endsWith("]")) {
ln = ln.substring("OK[".length(), ln.length() - 1);
try {
rs.setIndex(Integer.parseInt(ln));
return rs;
} catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
}
} else if(ln.startsWith("WRN")) {
parseWarning(ln, rs);
Client.getLogger().warning(rs.getMessage());
return rs;
} else if(ln.startsWith("ERR:")) {
parseError(ln, rs);
throw new LSException(rs.getCode(), rs.getMessage());
}
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!") );
}
/**
* Parses warning message.
* @param ln The warning message to be parsed.
* @param rs A ResultSet
instance where the warning must be stored.
* @throws LscpException If LSCP protocol corruption occurs.
*/
protected static void
parseWarning(String ln, ResultSet rs) throws LscpException {
if(!ln.startsWith("WRN"))
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
int i, j;
rs.setWarning(true);
if(ln.charAt(3) == '[') {
i = ln.indexOf(']');
if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
try {
j = Integer.parseInt(ln.substring("WRN[".length(), i));
rs.setIndex(j);
} catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
}
if(ln.charAt(i + 1) != ':')
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
}
i = ln.indexOf(':');
if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
j = ln.indexOf(':', i + 1);
if(j == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
try { rs.setCode(Integer.parseInt(ln.substring(i + 1, j))); }
catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
}
rs.setMessage(ln.substring(j + 1));
}
/**
* Parses error message.
* @param ln The error message to be parsed.
* @param rs A ResultSet
instance where the error must be stored.
* @throws LscpException If LSCP protocol corruption occurs.
*/
protected static void
parseError(String ln, ResultSet rs) throws LscpException {
if(!ln.startsWith("ERR:"))
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
int i = ln.indexOf(':', "ERR:".length());
if(i == -1) throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
try { rs.setCode(Integer.parseInt(ln.substring("ERR:".length(), i))); }
catch(NumberFormatException x) {
throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"), x);
}
rs.setMessage(ln.substring(i + 1));
}
/**
* Gets the info character string to the specified information category.
* @param resultSet A String
array containing the information categories
* of a multi-line result set.
* @param category Specifies the category whose info character string to be returned.
* @return The info character string to the specified information category or
* null
if the specified result set does not contain that category.
*/
protected static String
getCategoryInfo(String[] resultSet, String category) {
String c = category + ": ";
for(String s : resultSet)
if(s.startsWith(c)) return s.substring(c.length(), s.length());
return null;
}
}