/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.io.charset;
import avt.lang.array.*;
import avt.lang.table.*;
import platform.dependent.*;
public abstract class Charset(Object, Comparable)
{
private static int count;
private static Charset[] charsets;
private static final Charset utf8;
private static final Charset consoleInput;
private static final Charset consoleOutput;
private static final String inputCharsetName;
private static final String outputCharsetName;
private static final KeyValueTable registered;
public static {
registered = new KeyValueTable();
charsets = new Charset[0x0fi];
for(String packPrefix = "avt.io.charset.", Package[] packs = Package.enumerate(), int packIndex = packs.length; packIndex-- > 0; )
{
Package pack = packs[packIndex];
if(pack.canonicalName.startsWith(packPrefix)) for(Class[] types = pack.enumerateTypes(), int typeIndex = types.length; typeIndex-- > 0; )
{
Class type = types[typeIndex];
if(!type.isAbstract() && type.visibility >= ReflectiveObject.PUBLIC && Charset.class.isAssignableFrom(type))
{
try
{
registerCharset((Charset) type.newInstance());
}
catch(Exception exception)
{
exception.printStackTrace();
}
}
}
}
utf8 = getCharset("UTF-8");
ProcessEnvironment env = System.getCurrentProcessEnv();
consoleInput = getCharset(inputCharsetName = env.consoleInputCharsetName);
consoleOutput = getCharset(outputCharsetName = env.consoleOutputCharsetName);
}
public static void register(Charset charset) throws RegisteredCharsetNameException {
if(charset == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "charset" }));
}
String charsetName = null;
synchronized(registered)
{
label0:
{
String currentName;
if(registered.contains(currentName = charset.fldName))
{
charsetName = currentName;
break label0;
}
for(String[] aliases = charset.fldAliases, int index = aliases.length; index-- > 0; ) if(registered.contains(currentName = aliases[index]))
{
charsetName = currentName;
break label0;
}
registerCharset(charset);
}
}
if(charsetName != null)
{
throw new RegisteredCharsetNameException(package.getResourceString("registered-charset-name")) { charsetName = charsetName };
}
}
public static boolean isSupported(String charsetName) { return registered.contains(charsetName); }
public static Charset[] enumerate() {
Charset[] result;
synchronized(registered)
{
Array.copy(charsets, 0, result = new Charset[count], 0, count);
}
return result;
}
public static Charset getDefault() { return utf8; }
public static Charset getConsoleInput() throws UnsupportedCharsetNameException {
if(consoleInput == null)
{
throw new UnsupportedCharsetNameException(package.getResourceString("unsupported-charset-name")) { charsetName = inputCharsetName };
}
return consoleInput;
}
public static Charset getConsoleOutput() throws UnsupportedCharsetNameException {
if(consoleOutput == null)
{
throw new UnsupportedCharsetNameException(package.getResourceString("unsupported-charset-name")) { charsetName = outputCharsetName };
}
return consoleOutput;
}
public static Charset get(String charsetName) throws UnsupportedCharsetNameException {
if(charsetName == null) charsetName = "";
Charset result = (Charset) registered[charsetName];
if(result == null)
{
throw new UnsupportedCharsetNameException(package.getResourceString("unsupported-charset-name")) { charsetName = charsetName };
}
return result;
}
private static void registerCharset(Charset charset) {
if(count == Int.MAX_VALUE)
{
throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
}
if(count == charsets.length)
{
Array.copy(charsets, 0, charsets = new Charset[count << 1 | 1], 0, count);
}
charsets[count++] = charset;
registered[charset.fldName] = charset;
for(String[] aliases = charset.fldAliases, int index = aliases.length; index-- > 0; ) registered[aliases[index]] = charset;
}
private static Charset getCharset(String charsetName) { return (Charset) registered[charsetName == null ? "" : charsetName]; }
private final String[] fldAliases;
private final String fldName;
protected (String name, String[] aliases) {
int alength = aliases == null ? 0 : aliases.length;
String charsetName = name == null ? "" : name;
String[] charsetAliases = new String[alength];
label0: for(int length = alength, alength = 0, int ali = 0; ali < length; ali++)
{
String alias = aliases[ali];
if(alias == null || alias.equals(charsetName))
{
continue label0;
}
for(int alj = alength; alj-- > 0; ) if(alias.equals(charsetAliases[alj]))
{
continue label0;
}
charsetAliases[alength++] = alias;
}
if(alength != charsetAliases.length)
{
Array.copy(charsetAliases, 0, charsetAliases = new String[alength], 0, alength);
}
charsetAliases.finalize();
fldAliases = charsetAliases;
fldName = charsetName;
}
public abstract CharDecoder newDecoder();
public abstract CharEncoder newEncoder();
public boolean contains(Charset charset) { return false; }
public String displayName() { return fldName; }
public final boolean equals(Object anot) { return anot == this || anot instanceof Charset && ((Charset) anot).fldName.equals(fldName); }
public final int hashCode() { return ((Object) fldName).hashCode(); }
public final long hashCodeAsLong() { return ((Object) fldName).hashCodeAsLong(); }
public final long2 hashCodeAsLong2() { return ((Object) fldName).hashCodeAsLong2(); }
public final long4 hashCodeAsLong4() { return ((Object) fldName).hashCodeAsLong4(); }
public final long8 hashCodeAsLong8() { return ((Object) fldName).hashCodeAsLong8(); }
public final String toString() { return "charset " + fldName; }
public final int compareTo(Comparable anot) { return !(anot instanceof Charset) ? INDEFINITE : -((Charset) anot).fldName.compareTo(fldName); }
public final boolean isRegistered() {
boolean result;
synchronized(registered)
{
result = count > 0 && Array.indexOf(this, charsets, 0, count) >= 0;
}
return result;
}
public final boolean isName(String charsetName) {
if(charsetName == null)
{
charsetName = "";
}
if(fldName.equals(charsetName))
{
return true;
}
for(String[] aliases = fldAliases, int index = aliases.length; index-- > 0; ) if(aliases[index].equals(charsetName))
{
return true;
}
return false;
}
public final char[] decode(ByteArray src) {
try
{
return newDecoder().decode(src);
}
catch(Exception exception)
{
throw exception instanceof RuntimeException ? (RuntimeException) exception : new UnsupportedOperationException(exception.message, exception);
}
}
public final char[] decode(ByteArray src, int offset, int length) {
try
{
return newDecoder().decode(src, offset, length);
}
catch(Exception exception)
{
throw exception instanceof RuntimeException ? (RuntimeException) exception : new UnsupportedOperationException(exception.message, exception);
}
}
public final byte[] encode(CharArray src) {
try
{
return newEncoder().encode(src);
}
catch(Exception exception)
{
throw exception instanceof RuntimeException ? (RuntimeException) exception : new UnsupportedOperationException(exception.message, exception);
}
}
public final byte[] encode(CharArray src, int offset, int length) {
try
{
return newEncoder().encode(src, offset, length);
}
catch(Exception exception)
{
throw exception instanceof RuntimeException ? (RuntimeException) exception : new UnsupportedOperationException(exception.message, exception);
}
}
public final String[] aliases { read = fldAliases }
public final String name { read = fldName }
public final boolean operator >(Comparable anot) { return Comparable.super.operator >(anot); }
public final boolean operator >=(Comparable anot) { return Comparable.super.operator >=(anot); }
public final boolean operator <(Comparable anot) { return Comparable.super.operator <(anot); }
public final boolean operator <=(Comparable anot) { return Comparable.super.operator <=(anot); }
}