/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package java.lang;
import java.io.*;
import malik.emulator.io.jar.*;
import malik.emulator.util.*;
public final class Class extends Object
{
static final int PUBLIC = 0x0001;
static final int PRIVATE = 0x0002;
static final int PROTECTED = 0x0004;
static final int STATIC = 0x0008;
static final int FINAL = 0x0010;
static final int SYNCHRONIZED = 0x0020;
static final int VOLATILE = 0x0040;
static final int TRANSIENT = 0x0080;
static final int NATIVE = 0x0100;
static final int INTERFACE = 0x0200;
static final int ABSTRACT = 0x0400;
static final int STRICTFP = 0x0800;
static final int SYNTHETIC = 0x1000;
static final int PRIMITIVE = 0x00010000;
public static Class forName(String typeName) throws ClassNotFoundException {
boolean array;
int len;
if(typeName == null)
{
throw new ClassNotFoundException("Class.forName: класс с именем-нулевой ссылкой не найден.");
}
if((len = typeName.length()) <= 0)
{
throw new ClassNotFoundException("Class.forName: класс с пустым именем не найден.");
}
if((array = typeName.charAt(0) == '[') && len == 2) switch(typeName.charAt(1))
{
default:
break;
case 'Z':
return MalikSystem.getClassInstance("[Z");
case 'C':
return MalikSystem.getClassInstance("[C");
case 'F':
return MalikSystem.getClassInstance("[F");
case 'D':
return MalikSystem.getClassInstance("[D");
case 'B':
return MalikSystem.getClassInstance("[B");
case 'S':
return MalikSystem.getClassInstance("[S");
case 'I':
return MalikSystem.getClassInstance("[I");
case 'J':
return MalikSystem.getClassInstance("[J");
}
for(Class current = MalikSystem.getClassInstance("Ljava/lang/Object;"); current != null; current = current.nextType) if(typeName.equals(current.getName())) return current;
if(array) for(int lim = len - 1, dimc = 1; dimc < 0x0100 && dimc < len; dimc++)
{
switch(typeName.charAt(dimc))
{
default:
break;
case 'Z':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[Z"), dimc - 1);
}
break;
case 'C':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[C"), dimc - 1);
}
break;
case 'F':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[F"), dimc - 1);
}
break;
case 'D':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[D"), dimc - 1);
}
break;
case 'B':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[B"), dimc - 1);
}
break;
case 'S':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[S"), dimc - 1);
}
break;
case 'I':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[I"), dimc - 1);
}
break;
case 'J':
if(dimc == lim)
{
return createArrayType(MalikSystem.getClassInstance("[J"), dimc - 1);
}
break;
case 'L':
if(typeName.charAt(lim) == ';' && lim - dimc > 1 && typeName.charAt(dimc + 1) != '[')
{
return createArrayType(forName(typeName.substring(dimc + 1, lim)), dimc);
}
break;
case '[':
continue;
}
break;
}
throw new ClassNotFoundException((new StringBuilder()).append("Class.forName: класс ").append(typeName).append(" не найден.").toString());
}
private static Class findArrayType(Class componentType, int dimensionsMaximum) {
int dimensionsResult = componentType.getArrayDimensionsQuantity();
Class result = componentType;
if(dimensionsResult > 0)
{
dimensionsMaximum += dimensionsResult;
componentType = componentType.getCellType();
}
for(Class current = MalikSystem.getClassInstance("["); current != null; current = current.nextType)
{
int dimensionsCurrent;
if(current.getCellType() == componentType && (dimensionsCurrent = current.getArrayDimensionsQuantity()) > dimensionsResult && dimensionsCurrent <= dimensionsMaximum)
{
dimensionsResult = dimensionsCurrent;
result = current;
}
}
return result;
}
private static Class createArrayType(Class componentType, int dimensionsQuantity) {
boolean status;
Class result;
status = MalikSystem.enterMonopolyAccess();
try
{
result = findArrayType(componentType, dimensionsQuantity);
dimensionsQuantity -= result.getArrayDimensionsQuantity() - componentType.getArrayDimensionsQuantity();
for(; dimensionsQuantity-- > 0; result = new Class(result));
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
/*
* Нельзя менять порядок полей здесь, можно добавлять новые поля в конец списка.
*/
final int modifiers;
private final int instanceSize;
private final int nameIndex;
final int[] referenceOffsets;
private final int[] virtualAddresses;
private final long[] dynamicIndexesAndAddresses;
private final InterfaceEntry[] interfaceEntries;
final Class superType;
final Class componentType;
private Class nextType;
Thread initializingThread;
/*
* Новые поля можно добавлять только после этого комментария. Поля типов
* boolean, char, byte и short нельзя добавлять.
*/
private String name;
private String canonicalName;
private Class(Class componentType) {
int len;
int[] thisVirtuals;
int[] objectVirtuals;
Class firstArray = MalikSystem.getClassInstance("[");
Class object = MalikSystem.getClassInstance("Ljava/lang/Object;");
this.modifiers = FINAL | componentType.modifiers & (PUBLIC | PROTECTED | PRIVATE);
this.instanceSize = 0x10;
this.nameIndex = -1;
this.referenceOffsets = object.referenceOffsets;
this.virtualAddresses = thisVirtuals = new int[len = (objectVirtuals = object.virtualAddresses).length];
this.dynamicIndexesAndAddresses = object.dynamicIndexesAndAddresses;
this.interfaceEntries = new InterfaceEntry[0];
this.superType = object;
this.componentType = componentType;
this.nextType = firstArray.nextType;
this.name = (
componentType.isArray() ? (new StringBuilder()).append('[').append(componentType.getName()) : (new StringBuilder()).append("[L").append(componentType.getName()).append(';')
).toString();
MalikSystem.arraycopyf_int(objectVirtuals, 1, thisVirtuals, 1, len - 1);
firstArray.nextType = this;
}
public String toString() {
return (modifiers & PRIMITIVE) != 0 ? getName() : ((modifiers & INTERFACE) != 0 ? "interface " : "class ").concat(getName());
}
public boolean isArray() {
return componentType != null;
}
public boolean isInterface() {
return (modifiers & INTERFACE) != 0;
}
public boolean isInstance(Object reference) {
return reference != null && isAssignableFrom(reference.getClass());
}
public boolean isAssignableFrom(Class type) {
int modifiers;
int thisDimensions;
int typeDimensions;
if(type == null)
{
throw new NullPointerException("Class.isAssignableFrom: аргумент type равен нулевой ссылке.");
}
if(type == this)
{
return true;
}
if(((modifiers = type.modifiers) & PRIMITIVE) != 0)
{
return false;
}
if((modifiers & INTERFACE) != 0 || type.componentType == null)
{
return ((modifiers = this.modifiers) & INTERFACE) != 0 && type.isInterfaceImplements(this) || (modifiers & PRIMITIVE) == 0 && type.isInheritedFrom(this);
}
if((thisDimensions = this.getArrayDimensionsQuantity()) <= 0)
{
return this == MalikSystem.getClassInstance("Ljava/lang/Object;");
}
if((typeDimensions = type.getArrayDimensionsQuantity()) == thisDimensions)
{
return this.getCellType().isAssignableFrom(type.getCellType());
}
if(thisDimensions < typeDimensions)
{
return this.getCellType() == MalikSystem.getClassInstance("Ljava/lang/Object;");
}
return false;
}
public String getName() {
String result;
if((result = name) == null) result = name = StringPool.getString(nameIndex);
return result;
}
public String getCanonicalName() {
int len;
String result;
StringBuilder buffer;
if((result = canonicalName) != null) return result;
if((len = (buffer = new StringBuilder()).append(getName()).length()) > 0 && buffer.get(0) == '[')
{
int dimc;
for(dimc = 1; dimc < len && buffer.get(dimc) == '['; dimc++);
if(dimc < len)
{
buffer.delete(0, dimc);
len -= dimc;
switch(buffer.get(0))
{
default:
break;
case 'Z':
buffer.delete(0).append("boolean");
break;
case 'C':
buffer.delete(0).append("char");
break;
case 'F':
buffer.delete(0).append("float");
break;
case 'D':
buffer.delete(0).append("delete");
break;
case 'B':
buffer.delete(0).append("byte");
break;
case 'S':
buffer.delete(0).append("short");
break;
case 'I':
buffer.delete(0).append("int");
break;
case 'J':
buffer.delete(0).append("long");
break;
case 'L':
buffer.delete(0);
if(--len > 0 && buffer.get(--len) == ';') buffer.delete(len);
break;
}
for(int i = dimc; i-- > 0; buffer.append("[]"));
}
}
return canonicalName = buffer.toString().replace('$', '.');
}
public InputStream getResourceAsStream(String resourceName) {
int i;
String className;
ResourceStream result;
if(resourceName == null) return null;
if(resourceName.length() > 0 && resourceName.charAt(0) == '/')
{
resourceName = resourceName.substring(1);
}
else if((i = (className = getName()).lastIndexOf('.')) >= 0)
{
resourceName = className.substring(0, i + 1).replace('.', '/').concat(resourceName);
}
return (result = new ResourceStream("/res/".concat(resourceName), "/".concat(resourceName))).hasOpenError() ? null : result;
}
public Object newInstance() throws InstantiationException, IllegalAccessException {
Object result;
MalikSystem.invokeDefaultConstructor(result = allocateInstance(true));
return result;
}
boolean isInheritedFrom(Class type) {
for(Class current = superType; current != null; current = current.superType) if(current == type) return true;
return false;
}
boolean isInterfaceImplements(Class type) {
Class current = this;
do
{
InterfaceEntry[] entries;
for(int i = (entries = current.interfaceEntries).length; i-- > 0; ) if(entries[i].implementedInterface == type) return true;
} while((current = current.superType) != null);
return false;
}
int getArrayDimensionsQuantity() {
int result = 0;
for(Class current = componentType; current != null; current = current.componentType) result++;
return result;
}
int getInterfaceMethodEntryPoint(Class type, int offset) {
return getInterfaceEntry(type).interfaceMethodTableAddress + offset;
}
Class getCellType() {
Class result;
if((result = componentType) != null) for(Class current; (current = result.componentType) != null; result = current);
return result;
}
Object cast(Object reference) {
Class type;
if(reference != null && !isAssignableFrom(type = reference.getClass()))
{
throw new ClassCastException(
(new StringBuilder()).append("Class.cast: нельзя привести экземпляр типа ").append(type.getCanonicalName()).append(" к типу ").append(this.getCanonicalName()).append('.').toString()
);
}
return reference;
}
Object allocateInstance() {
Object result;
try
{
result = allocateInstance(false);
}
catch(Exception e)
{
throw new InstantiationError(e.getMessage());
}
return result;
}
Object allocateInstance(boolean useDefaultConstructor) throws InstantiationException, IllegalAccessException {
int modifiers;
if(componentType != null)
{
throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является массивом.").toString());
}
if(((modifiers = this.modifiers) & (ABSTRACT | INTERFACE | PRIMITIVE)) != 0)
{
if((modifiers & (ABSTRACT | INTERFACE)) != 0)
{
throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является абстрактным.").toString());
}
if((modifiers & PRIMITIVE) != 0)
{
throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является примитивным.").toString());
}
}
if(useDefaultConstructor)
{
if((modifiers & PUBLIC) == 0)
{
throw new IllegalAccessException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" не является открытым (public).").toString());
}
if(virtualAddresses[0] == 0)
{
throw new IllegalAccessException(
(new StringBuilder()).append("Class.newInstance: класс ").append(getCanonicalName()).append(" не имеет открытого (public) конструктора без аргументов.").toString()
);
}
}
return Memory.allocateInstanceOf(this, instanceSize, -1);
}
private InterfaceEntry getInterfaceEntry(Class type) {
Class current = this;
do
{
InterfaceEntry[] entries;
for(int i = (entries = current.interfaceEntries).length; i-- > 0; )
{
InterfaceEntry entry;
if((entry = entries[i]).implementedInterface == type) return entry;
}
} while((current = current.superType) != null);
return null;
}
}
final class InterfaceEntry extends Object
{
/* Нельзя менять порядок полей здесь, нельзя добавлять новые поля сюда. */
final int interfaceMethodTableAddress;
final Class implementedInterface;
public InterfaceEntry(int interfaceMethodTableAddress, Class implementedInterface) {
this.interfaceMethodTableAddress = interfaceMethodTableAddress;
this.implementedInterface = implementedInterface;
}
}