/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.midp.protocol;
import java.io.*;
public class URLParser extends Object
{
public static final int EMPTY_PORT = -1;
public static final String SEPARATOR = "://";
protected static final int PROTOCOL = 0;
protected static final int USER_INFO = 1;
protected static final int HOST_NAME = 2;
protected static final int PATH = 3;
protected static final int QUERY = 4;
protected int port;
protected String[] components;
protected ByteArrayOutputStream data;
public URLParser()
{
this.components = new String[5];
this.data = new ByteArrayOutputStream();
}
public void parse(String url)
{
int i;
int len;
String[] c;
if(url == null)
{
throw new IllegalArgumentException("Connector.open: " +
"параметр url равен нулевой ссылке.");
}
port = -1;
for(i = (c = components).length; i-- > 0; )
{
c[i] = null;
}
if((i = parsePath(url, parseTarget(url, parseSeparator(url,
parseProtocol(url, 0))))) < (len = url.length()) &&
url.charAt(i) == '?')
{
i = parseQuery(url, i);
}
if(i < len)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
}
public int getPort()
{
return port;
}
public String getHostName()
{
String[] c;
return (c = components) == null ? null : c[HOST_NAME];
}
public String getProtocol()
{
String[] c;
return (c = components) == null ? null : c[PROTOCOL];
}
public String getUserInfo()
{
String[] c;
return (c = components) == null ? null : c[USER_INFO];
}
public String getPath()
{
String[] c;
return (c = components) == null ? null : c[PATH];
}
public String getQuery()
{
String[] c;
return (c = components) == null ? null : c[QUERY];
}
protected int parseProtocol(String url, int startIndex)
{
char c;
int i;
int len;
ByteArrayOutputStream out;
for((out = data).reset(), len = url.length(), i = startIndex; i <= len; i++)
{
c = i < len ? url.charAt(i) : 0;
if(i == startIndex && ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')))
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if(i > startIndex && ((c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
(c < 'a' || c > 'z') && c != '+' && c != '-' && c != '.'))
{
break;
}
out.write((int) c);
}
components[PROTOCOL] = out.toString();
return i;
}
protected int parseSeparator(String url, int startIndex)
{
int i;
int j;
int len;
if(url.length() - startIndex < (len = SEPARATOR.length()))
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
for(i = startIndex, j = 0; j < len; i++, j++)
{
if(url.charAt(i) != SEPARATOR.charAt(j))
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
}
return i;
}
protected int parseUserInfo(String url, int startIndex)
{
char c;
int i;
int len;
int val;
ByteArrayOutputStream out;
for((out = data).reset(), len = url.length(), i = startIndex; i <= len; i++)
{
if(((c = i < len ? url.charAt(i) : 0) >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' ||
c == '\'' || c == '(' || c == ')' || c == ';' || c == ':' || c == '&' ||
c == '=' || c == '+' || c == '$' || c == ',')
{
out.write((int) c);
}
else if(c == '%')
{
if(++i > len - 2)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i++)) >= '0' && c <= '9')
{
val = c - '0';
}
else if(c >= 'A' && c <= 'F')
{
val = c - ('A' - 0x0a);
}
else if(c >= 'a' && c <= 'f')
{
val = c - ('a' - 0x0a);
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i)) >= '0' && c <= '9')
{
val = (val << 4) | (c - '0');
}
else if(c >= 'A' && c <= 'F')
{
val = (val << 4) | (c - ('A' - 0x0a));
}
else if(c >= 'a' && c <= 'f')
{
val = (val << 4) | (c - ('a' - 0x0a));
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
out.write(val);
}
else
{
break;
}
}
components[USER_INFO] = out.toString();
return i;
}
protected int parseHostName(String url, int startIndex)
{
char c;
int i;
int len;
ByteArrayOutputStream out;
for((out = data).reset(), len = url.length(), i = startIndex; i <= len; i++)
{
if(((c = i < len ? url.charAt(i) : 0) >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
c == '+' || c == '-' || c == '.')
{
out.write((int) c);
}
else
{
break;
}
}
components[HOST_NAME] = out.toString();
return i;
}
protected int parsePort(String url, int startIndex)
{
char c;
int i;
int len;
int val;
for(val = 0, len = url.length(), i = startIndex; i <= len; i++)
{
c = i < len ? url.charAt(i) : 0;
if(i == startIndex && (c < '0' || c > '9'))
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if(i > startIndex && (c < '0' || c > '9'))
{
break;
}
if((val = (val * 10) + (c - '0')) > 0xffff)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
}
port = val;
return i;
}
protected int parsePath(String url, int startIndex)
{
char c;
int i;
int len;
int val;
ByteArrayOutputStream out;
for((out = data).reset(), len = url.length(), i = startIndex; i <= len; i++)
{
if(((c = i < len ? url.charAt(i) : 0) >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' ||
c == '\'' || c == '(' || c == ')' || c == ':' || c == '@' || c == '&' ||
c == '=' || c == '+' || c == '$' || c == ',' || c == ';' || c == '/')
{
out.write((int) c);
}
else if(c == '%')
{
if(++i > len - 2)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i++)) >= '0' && c <= '9')
{
val = c - '0';
}
else if(c >= 'A' && c <= 'F')
{
val = c - ('A' - 0x0a);
}
else if(c >= 'a' && c <= 'f')
{
val = c - ('a' - 0x0a);
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i)) >= '0' && c <= '9')
{
val = (val << 4) | (c - '0');
}
else if(c >= 'A' && c <= 'F')
{
val = (val << 4) | (c - ('A' - 0x0a));
}
else if(c >= 'a' && c <= 'f')
{
val = (val << 4) | (c - ('a' - 0x0a));
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
out.write(val);
}
else
{
break;
}
}
components[PATH] = out.toString();
return i;
}
protected int parseQuery(String url, int startIndex)
{
char c;
int i;
int len;
int val;
ByteArrayOutputStream out;
for((out = data).reset(), len = url.length(), i = startIndex; i <= len; i++)
{
if(((c = i < len ? url.charAt(i) : 0) >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' ||
c == '\'' || c == '(' || c == ')' || c == ';' || c == '/' || c == '?' ||
c == ':' || c == '@' || c == '&' || c == '=' || c == '+' || c == '$' ||
c == ',')
{
out.write((int) c);
}
else if(c == '%')
{
if(++i > len - 2)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i++)) >= '0' && c <= '9')
{
val = c - '0';
}
else if(c >= 'A' && c <= 'F')
{
val = c - ('A' - 0x0a);
}
else if(c >= 'a' && c <= 'f')
{
val = c - ('a' - 0x0a);
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
if((c = url.charAt(i)) >= '0' && c <= '9')
{
val = (val << 4) | (c - '0');
}
else if(c >= 'A' && c <= 'F')
{
val = (val << 4) | (c - ('A' - 0x0a));
}
else if(c >= 'a' && c <= 'f')
{
val = (val << 4) | (c - ('a' - 0x0a));
}
else
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
out.write(val);
}
else
{
break;
}
}
components[QUERY] = out.toString();
return i;
}
protected int parseTarget(String url, int startIndex)
{
char c;
int i;
int len;
int atIndex = -1;
int colonIndex = -1;
int finishIndex;
for(len = url.length(), i = startIndex; i <= len; i++)
{
if((c = i < len ? url.charAt(i) : 0) == '/' || c == '?' || c == 0)
{
break;
}
switch(c)
{
case '@':
atIndex = i;
break;
case ':':
colonIndex = i;
break;
}
}
if(colonIndex < atIndex)
{
colonIndex = -1;
}
if(atIndex >= 0)
{
if(colonIndex >= 0)
{
if(parseUserInfo(url, startIndex) != atIndex ||
parseHostName(url, atIndex + 1) != colonIndex)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
finishIndex = parsePort(url, colonIndex + 1);
} else
{
if(parseUserInfo(url, startIndex) != atIndex)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
finishIndex = parseHostName(url, atIndex + 1);
}
} else
{
if(colonIndex >= 0)
{
if(parseHostName(url, startIndex) != colonIndex)
{
throw new IllegalArgumentException("Connector.open: " +
"недопустимое значение параметра url.");
}
finishIndex = parsePort(url, colonIndex + 1);
} else
{
finishIndex = parseHostName(url, startIndex);
}
}
return finishIndex;
}
}