/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.io.*;
import avt.io.charset.*;
public final class Package(RequiredReflectiveObject)
{
public static Package get(String canonicalName) throws PackageNotFoundException {
Package result = find(canonicalName);
if(result == null)
{
throw new PackageNotFoundException(package.getResourceString("not-found.package")) { canonicalName = canonicalName };
}
return result;
}
public static Package[] enumerate() {
int length = 1;
Package[] result = new Package[0x0f];
for(Package current = (result[0] = void.class.parentPackage).getNext(); current != null; current = current.getNext())
{
if(length == result.length) Array.copy(result, 0, result = new Package[length << 1 | 1], 0, length);
result[length++] = current;
}
if(length != result.length) Array.copy(result, 0, result = new Package[length], 0, length);
return result;
}
package static Package find(String canonicalName) {
Package start = void.class.parentPackage;
if(canonicalName == null || canonicalName.isEmpty()) return start;
for(Package current = start.getNext(); current != null; current = current.getNext()) if(canonicalName.equals(current.canonicalName)) return current;
return null;
}
private static void writeChar(StringBuilder dst, int b0, int b1, int b2) {
switch(b0 >> 4)
{
default:
{
dst.append((char) b0);
break;
}
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
{
dst.append((char) (b0 & 0x3f));
break;
}
case 0x0c:
case 0x0d:
{
dst.append((char) ((b0 & 0x1f) << 6 | (b1 & 0x3f)));
break;
}
case 0x0e:
case 0x0f:
{
dst.append((char) ((b0 & 0x0f) << 12 | (b1 & 0x3f) << 6 | (b2 & 0x3f)));
break;
}
}
}
private final int fldReserved28;
private final int fldReserved2C;
private final int fldReserved30;
private final int fldReserved34;
private final int fldReserved38;
private final int fldDeclaredTypesCount;
private final int fldReserved40;
private final int fldReserved44;
private final int fldReserved48;
private final int fldReserved4C;
private final int fldReserved50;
private final int fldReserved54;
private final int fldReserved58;
private final int fldDeclaredTypesOffset;
private final int fldReserved60;
private final int fldReserved64;
private final int fldReserved68;
private final int fldReserved6C;
private final int fldReserved70;
private final int fldReserved74;
private final int fldReserved78;
private final int fldReserved7C;
private final long fldReserved80;
private final long fldReserved88;
private final long fldNextPackageOffset;
private final long fldReserved98;
private final long fldReservedA0;
private final long fldReservedA8;
private final long fldReservedB0;
private final int fldReservedB8;
private final int fldRequiredReflectiveObjectSize;
private int fldAddedTypesLength;
private Class[] fldAddedTypesArray;
private String fldCanonicalName;
private String fldSimpleName;
private () { }
public boolean isAbstract() { return false; }
public boolean isFinal() { return false; }
public String toString() { return "package " + getCanonicalName(); }
public Class[] enumerateTypes() {
int declared = fldDeclaredTypesCount;
int length = 0;
Class[] result = new Class[declared];
for(int index = 0; index < declared; index++)
{
Class current = getDeclaredType(index);
if(current.isArray())
{
Class component = current.componentType;
if(!component.isPrimitive() && component != Object.class) continue;
}
result[length++] = current;
}
if(declared != length) Array.copy(result, 0, result = new Class[length], 0, length);
return result;
}
public String[] enumerateResources() {
int length = 0;
String[] result = new String[0x0f];
for(String prefix = getResourcePrefix(), int offset = prefix.length, ResourceEnumerator resEnum = new ResourceEnumerator(); resEnum.hasMoreResources(); resEnum.nextResource())
{
String current = resEnum.getName();
if(current != null && current.startsWith(prefix))
{
if(length == result.length) Array.copy(result, 0, result = new String[length << 1 | 1], 0, length);
result[length++] = current.substring(offset);
}
}
if(length != result.length) Array.copy(result, 0, result = new String[length], 0, length);
return result;
}
public String getResourceString(String name) {
if(name == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "name" }));
}
ByteArrayInputStream stream = createResourceStream(name + ".txt");
if(stream == null) return null;
StringBuilder result = new StringBuilder();
label0: for(int b0 = 0, int b1 = 0, int br = 0; ; )
{
int bt = stream.read();
switch(bt >> 4)
{
default:
{
if(br > 0) writeChar(result, b0, br > 1 ? b1 : 0, 0);
break label0;
}
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
{
if(br > 0) writeChar(result, b0, br > 1 ? b1 : 0, 0);
writeChar(result, bt, 0, 0);
br = 0;
break;
}
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
{
if(br > 0) writeChar(result, b0, br > 1 ? b1 : 0, 0);
b0 = bt;
br = 1;
break;
}
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
{
switch(br)
{
default:
{
writeChar(result, bt, 0, 0);
break;
}
case 1:
{
if((b0 >> 4) < 0x0e)
{
writeChar(result, b0, bt, 0);
br = 0;
break;
}
b1 = bt;
br = 2;
break;
}
case 2:
{
br = 0;
if((b0 >> 4) < 0x0e)
{
writeChar(result, b0, b1, 0);
writeChar(result, bt, 0, 0);
break;
}
writeChar(result, b0, b1, bt);
}
}
}
}
}
return result.toString();
}
public String getResourceString(String name, Charset charset) {
if(name == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "name" }));
}
ByteArrayInputStream stream = createResourceStream(name + ".txt");
if(stream == null) return null;
int length = (int) stream.size();
byte[] bytes = new byte[length];
stream.read(bytes, 0, length);
return new String((charset != null ? charset : Charset.getDefault()).decode(bytes, 0, length));
}
public String getResourceString(String name, CharDecoder decoder) throws CharDecodingException {
if(name == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "name" }));
}
ByteArrayInputStream stream = createResourceStream(name + ".txt");
if(stream == null) return null;
int length = (int) stream.size();
byte[] bytes = new byte[length];
stream.read(bytes, 0, length);
return new String((decoder != null ? decoder : Charset.getDefault().newDecoder()).decode(bytes, 0, length));
}
public ByteReader openResource(String name) {
if(name == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "name" }));
}
return createResourceStream(name);
}
public String simpleName { read = getSimpleName }
public String canonicalName { read = getCanonicalName }
package void addArrayType(Class type) {
int length = fldAddedTypesLength;
Class[] array = fldAddedTypesArray;
if(array == null)
{
fldAddedTypesArray = array = new Class[0x0f];
} else if(length == array.length)
{
Array.copy(array, 0, fldAddedTypesArray = array = new Class[length << 1 | 1], 0, length);
}
array[length++] = type;
fldAddedTypesLength = length;
}
package Class findAddedArrayType(Class componentType) {
if(componentType != null) for(Class[] array = fldAddedTypesArray, int length = fldAddedTypesLength, int index = 0; index < length; index++)
{
Class current = array[index];
if(componentType == current.componentType) return current;
}
return null;
}
package Class findDeclaredType(String simpleName) {
if(simpleName != null) for(int length = fldDeclaredTypesCount, int index = 0; index < length; index++)
{
Class current = getDeclaredType(index);
if(simpleName.equals(current.simpleName)) return current;
}
return null;
}
private native Class getDeclaredType(int index);
private String getSimpleName() {
String canonicalName = getCanonicalName();
return canonicalName.substring(canonicalName.lastIndexOf('.') + 1);
}
private String getCanonicalName() {
String result = fldCanonicalName;
return result != null ? result : fldCanonicalName = String.getConstant(fldNameIndex);
}
private String getResourcePrefix() {
String canonicalName = getCanonicalName();
return canonicalName.isEmpty() ? "/" : (new StringBuilder()).append('/').append(canonicalName.replaceAll('.', '/')).append('/').toString();
}
private native Package getNext();
private ByteArrayInputStream createResourceStream(String name) {
if(!name.startsWith("/")) name = getResourcePrefix() + name;
for(int length = name.length, int hash = name.hashCode(), ResourceEnumerator resEnum = new ResourceEnumerator(); resEnum.hasMoreResources(); resEnum.nextResource())
{
if(length == resEnum.nameLength && hash == resEnum.nameHash && name.equals(resEnum.getName())) return new ByteArrayInputStream(resEnum.getData());
}
return null;
}
}
class ResourceEnumerator(Object)
{
private int fldNameHash;
private int fldNameLength;
private int fldDataLength;
private long fldNamePointer;
private long fldDataPointer;
private long fldResourcePointer;
public () { initialize(); }
public native void nextResource();
public boolean hasMoreResources() { return fldNameLength > 0; }
public byte[] getData() {
if(fldNameLength <= 0) return null;
byte[] result = null;
try
{
result = (byte[]) byte[].class.newArrayAt(fldDataPointer, fldDataLength);
} catch(Exception exception)
{
exception.printStackTrace();
}
return result;
}
public String getName() {
int nameLength = fldNameLength;
if(nameLength <= 0) return null;
char[] nameChars = null;
try
{
for(byte[] nameBytes = (byte[]) byte[].class.newArrayAt(fldNamePointer, nameLength), int index = nameBytes.length, nameChars = new char[index]; index-- > 0; )
{
nameChars[index] = (char) (nameBytes[index] & 0xffi);
}
} catch(Exception exception)
{
exception.printStackTrace();
}
return nameChars == null ? null : new String(nameChars);
}
public int nameHash { read = fldNameHash }
public int nameLength { read = fldNameLength }
public int dataLength { read = fldDataLength }
private native void initialize();
}