mikrotik-java/src/main/java/me/legrange/mikrotik/impl/Util.java

176 lines
6.1 KiB
Java

package me.legrange.mikrotik;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
/**
* Utility library that handles the low level encoding required by the Mikrotik API.
* @author GideonLeGrange. Possibly some code by janisk left.
*/
class Util {
static void write(Command cmd, OutputStream out) throws UnsupportedEncodingException, IOException {
encode(cmd.getCommand(), out);
for (Parameter param : cmd.getParameters()) {
encode(String.format("=%s=%s", param.getName(), param.hasValue() ? param.getValue() : "" ), out);
}
String tag = cmd.getTag();
if ((tag != null) && !tag.equals("")) {
encode(String.format(".tag=%s", tag), out);
}
List<String> props = cmd.getProperties();
if (!props.isEmpty()) {
StringBuilder buf = new StringBuilder("=.proplist=");
for (int i = 0; i < props.size(); ++i) {
if (i > 0)
buf.append(",");
buf.append(props.get(i));
}
encode(buf.toString(), out);
}
for (String query : cmd.getQueries()) {
encode(query, out);
}
out.write(0);
}
/** encode text using Mikrotik's encoding scheme and write it to an output stream. */
private static void encode(String word, OutputStream out) throws UnsupportedEncodingException, IOException {
byte bytes[] = word.getBytes("US-ASCII");
int len = bytes.length;
if (len < 0x80) {
out.write(len);
} else if (len < 0x4000) {
len = len | 0x8000;
out.write(len >> 8);
out.write(len);
} else if (len < 0x20000) {
len = len | 0xC00000;
out.write(len >> 16);
out.write(len >> 8);
out.write(len);
} else if (len < 0x10000000) {
len = len | 0xE0000000;
out.write(len >> 24);
out.write(len >> 16);
out.write(len >> 8);
out.write(len);
} else {
out.write(0xF0);
out.write(len >> 24);
out.write(len >> 16);
out.write(len >> 8);
out.write(len);
}
out.write(bytes);
}
/** decode bytes from an input stream of Mikrotik protocol sentences into text */
static String decode(InputStream in) throws ApiDataException, ApiConnectionException {
StringBuilder res = new StringBuilder();
decode(in, res);
return res.toString();
}
/** decode bytes from an input stream into Mikrotik protocol sentences */
private static void decode(InputStream in, StringBuilder result) throws ApiDataException, ApiConnectionException {
try {
int len = readLen(in);
if (len > 0) {
byte buf[] = new byte[len];
for (int i = 0; i < len; ++i) {
int c = in.read();
if (c < 0) {
throw new ApiDataException("Truncated data. Expected to read more bytes");
}
buf[i] = (byte) (c & 0xFF);
}
String res = new String(buf);
if (result.length() > 0)
result.append("\n");
result.append(res);
decode(in, result);
}
} catch (IOException ex) {
throw new ApiConnectionException(ex.getMessage(), ex);
}
}
/** read length bytes from stream and return length of coming word */
static private int readLen(InputStream in) throws IOException {
int c = in.read();
if (c > 0) {
if ((c & 0x80) == 0) {
} else if ((c & 0xC0) == 0x80) {
c = c & ~0xC0;
c = (c << 8) | in.read();
} else if ((c & 0xE0) == 0xC0) {
c = c & ~0xE0;
c = (c << 8) | in.read();
c = (c << 8) | in.read();
} else if ((c & 0xF0) == 0xE0) {
c = c & ~0xF0;
c = (c << 8) | in.read();
c = (c << 8) | in.read();
c = (c << 8) | in.read();
} else if ((c & 0xF8) == 0xF0) {
c = in.read();
c = (c << 8) | in.read();
c = (c << 8) | in.read();
c = (c << 8) | in.read();
c = (c << 8) | in.read();
}
}
return c;
}
/**
* makes MD5 hash of string for use with RouterOS API
*
* @param s - variable to make hash from
* @return - the md5 hash
*/
static String hashMD5(String s) throws ApiDataException {
MessageDigest algorithm = null;
try {
algorithm = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
throw new ApiDataException("Cannot find MD5 digest algorithm");
}
byte[] defaultBytes = new byte[s.length()];
for (int i = 0; i < s.length(); i++) {
defaultBytes[i] = (byte) (0xFF & s.charAt(i));
}
algorithm.reset();
algorithm.update(defaultBytes);
byte messageDigest[] = algorithm.digest();
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < messageDigest.length; i++) {
String hex = Integer.toHexString(0xFF & messageDigest[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
/**
* converts hex value string to normal strint for use with RouterOS API
*
* @param s - hex string to convert to
* @return - converted string.
*/
static String hexStrToStr(String s) {
String ret = "";
for (int i = 0; i < s.length(); i += 2) {
ret += (char) Integer.parseInt(s.substring(i, i + 2), 16);
}
return ret;
}
}