/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.io.charset;
import avt.lang.array.*;
import avt.lang.util.*;
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 KeyValueTable registered;
public static {
charsets = new Charset[0x0f];
registered = new KeyValueTable();
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 = (Charset) registered["UTF-8"];
}
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) {
synchronized(registered)
{
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 { return get(PlatformServices.getInstance().getConsoleInputCharsetName()); }
public static Charset getConsoleOutput() throws UnsupportedCharsetNameException { return get(PlatformServices.getInstance().getConsoleOutputCharsetName()); }
public static Charset get(String charsetName) throws UnsupportedCharsetNameException {
if(charsetName == null) charsetName = "";
Charset result;
synchronized(registered)
{
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 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 index = 0; index < length; index++)
{
String alias = aliases[index];
if(alias == null || alias.equals(charsetName)) continue label0;
for(int aindex = alength; aindex-- > 0; ) if(alias.equals(charsetAliases[aindex])) 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); }
}