/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии 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(String.format(package.getResourceString("not-found.package"), new Object[] { canonicalName }));
}
return result;
}
public static Package[] enumerate() {
int length = 1;
Package[] result = new Package[0x0fi];
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 + (char) b0;
break;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
dst + (char) (b0 & 0x3f);
break;
case 0x0c:
case 0x0d:
dst + (char) ((b0 & 0x1f) << 6 | (b1 & 0x3f));
break;
case 0x0e:
case 0x0f:
dst + (char) ((b0 & 0x0f) << 12 | (b1 & 0x3f) << 6 | (b2 & 0x3f));
}
}
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 lengthDeclared = fldDeclaredTypesCount;
int lengthResult = 0;
Class[] result = new Class[lengthDeclared];
for(int index = 0; index < lengthDeclared; index++)
{
Class current = getDeclaredType(index);
if(current.isArray())
{
Class component = current.componentType;
if(!component.isPrimitive() && component != Object.class) continue;
}
result[lengthResult++] = current;
}
if(lengthDeclared != lengthResult)
{
Array.copy(result, 0, result = new Class[lengthResult], 0, lengthResult);
}
return result;
}
public String[] enumerateResources() {
int length = 0;
String[] result = new String[0x0fi];
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 CharacterDecodingException {
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[0x0fi];
}
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() + '/' + canonicalName.replaceAll('.', '/') + '/').toString();
}
private native Package getNext();
private ByteArrayInputStream createResourceStream(String name) {
if(!name.startsWith("/"))
{
name = getResourcePrefix() + name;
}
for(int nameLength = name.length, int nameHash = name.hashCode(), ResourceEnumerator resEnum = new ResourceEnumerator(); resEnum.hasMoreResources(); resEnum.nextResource())
{
if(nameLength == resEnum.nameLength && nameHash == 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 fldNameHash != 0; }
public byte[] getData() {
if(fldNameHash == 0) return null;
byte[] result = null;
try
{
result = (byte[]) byte[].class.newArrayAt(fldDataPointer, fldDataLength);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return result;
}
public String getName() {
if(fldNameHash == 0) return null;
char[] nameChars = null;
try
{
for(byte[] nameBytes = (byte[]) byte[].class.newArrayAt(fldNamePointer, fldNameLength), 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();
}