emulators/springcoat-vm/src/main/java/cc/squirreljme/vm/springcoat/MLEJarPackage.java
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package cc.squirreljme.vm.springcoat;
import cc.squirreljme.emulator.vm.VMSuiteManager;
import cc.squirreljme.jvm.manifest.JavaManifest;
import cc.squirreljme.jvm.manifest.JavaManifestAttributes;
import cc.squirreljme.jvm.mle.JarPackageShelf;
import cc.squirreljme.jvm.mle.brackets.JarPackageBracket;
import cc.squirreljme.runtime.cldc.debug.ErrorCode;
import cc.squirreljme.vm.OverlayVMClassLibrary;
import cc.squirreljme.vm.RawVMClassLibrary;
import cc.squirreljme.vm.VMClassLibrary;
import cc.squirreljme.vm.springcoat.brackets.JarPackageObject;
import cc.squirreljme.vm.springcoat.exceptions.SpringMLECallError;
import cc.squirreljme.vm.springcoat.exceptions.SpringVirtualMachineException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import net.multiphasicapps.classfile.MethodDescriptor;
/**
* Functions for {@link JarPackageShelf}.
*
* @since 2020/06/18
*/
public enum MLEJarPackage
implements MLEFunction
{
/** {@link JarPackageShelf#classPath()}. */
CLASS_PATH("classPath:()[Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;")
{
/**
* {@inheritDoc}
* @since 2020/06/18
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
VMClassLibrary[] springPath = __thread.machine.classloader
.classPath();
// Wrap the classpath in package objects
int n = springPath.length;
SpringObject[] rv = new SpringObject[n];
for (int i = 0; i < n; i++)
rv[i] = new JarPackageObject(__thread.machine, springPath[i]);
// Wrap
return __thread.asVMObjectArray(__thread.resolveClass(
"[Lcc/squirreljme/jvm/mle/brackets/JarPackageBracket;"),
rv);
}
},
/** {@link JarPackageShelf#equals(JarPackageBracket, JarPackageBracket)}.*/
EQUALS("equals:(Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;)Z")
{
/**
* {@inheritDoc}
* @since 2020/07/06
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
return MLEJarPackage.__jarObject(__args[0]).library() ==
MLEJarPackage.__jarObject(__args[1]).library();
}
},
/** {@link JarPackageShelf#libraries()}. */
LIBRARIES("libraries:()[Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;")
{
/**
* {@inheritDoc}
* @since 2020/10/31
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
VMSuiteManager suites = __thread.machine.suites;
String[] names = suites.listLibraryNames();
int n = names.length;
// Load each library as a reference
SpringObject[] result = new SpringObject[n];
for (int i = 0; i < n; i++)
result[i] = new JarPackageObject(__thread.machine,
suites.loadLibrary(names[i]));
return __thread.asVMObjectArray(__thread.resolveClass(
"[Lcc/squirreljme/jvm/mle/brackets/JarPackageBracket;"),
result);
}
},
/** {@link JarPackageShelf#libraryId(JarPackageBracket)}. */
LIBRARY_ID("libraryId:(Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;)I")
{
/**
* {@inheritDoc}
* @since 2023/12/18
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
return __thread.machine.suites.libraryId(
MLEJarPackage.__jarObject(__args[0]).library());
}
},
/** {@link JarPackageShelf#libraryPath(JarPackageBracket)}. */
LIBRARY_PATH("libraryPath:(Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;)Ljava/lang/String;")
{
/**
* {@inheritDoc}
* @since 2020/06/18
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
return MLEJarPackage.__jarObject(__args[0]).library().name();
}
},
/** {@link JarPackageShelf#openResource(JarPackageBracket, String)}. */
OPEN_RESOURCE("openResource:(Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;Ljava/lang/String;)Ljava/io/InputStream;")
{
/**
* {@inheritDoc}
* @since 2020/06/18
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
JarPackageObject jar = MLEJarPackage.__jarObject(__args[0]);
String rcName = __thread.<String>asNativeObject(
String.class, __args[1]);
if (rcName == null)
throw new SpringMLECallError("Null resource string.");
// Locate the resource
try (InputStream in = jar.library().resourceAsStream(rcName))
{
// Not found
if (in == null)
return SpringNullObject.NULL;
return __thread.proxyInputStream(in);
}
// Could not read it
catch (IOException e)
{
throw new SpringVirtualMachineException(
"Failed to read resource", e);
}
}
},
/** {@link JarPackageShelf#prefixCode(JarPackageBracket)}. */
PREFIX_CODE("prefixCode:(Lcc/squirreljme/jvm/mle/brackets/" +
"JarPackageBracket;)I")
{
/**
* {@inheritDoc}
* @since 2023/07/19
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
if (__args[0] == null)
throw new SpringMLECallError("No JAR specified.");
JarPackageObject __jar = MLEJarPackage.__jarObject(__args[0]);
// Load manifest to get the info
try (InputStream in = __jar.library()
.resourceAsStream("META-INF/MANIFEST.MF"))
{
if (in == null)
return -1;
// Load in manifest
JavaManifest manifest = new JavaManifest(in);
// Load in value
String value = manifest.getMainAttributes()
.getValue(ErrorCode.PREFIX_PROPERTY);
if (value == null)
return -1;
// Too short?
if (value.length() < 2)
return -1;
// Get both characters for radix calculation
char a = value.charAt(0);
char b = value.charAt(1);
// Calculate prefix code
return (Character.digit(a, Character.MAX_RADIX) *
Character.MAX_RADIX) +
Character.digit(b, Character.MAX_RADIX);
}
catch (IOException ignored)
{
return -1;
}
}
},
/**
* {@link JarPackageShelf#rawData(JarPackageBracket, int, byte[], int,
* int)}.
*/
RAW_DATA("rawData:(" +
"Lcc/squirreljme/jvm/mle/brackets/JarPackageBracket;I[BII)I")
{
/**
* {@inheritDoc}
* @since 2022/03/05
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
if (__args[0] == null)
throw new SpringMLECallError("No JAR specified.");
JarPackageObject __jar = MLEJarPackage.__jarObject(__args[0]);
int __jarOffset = (int)__args[1];
byte[] __b = ((SpringArrayObjectByte)__args[2]).array();
int __o = (int)__args[3];
int __l = (int)__args[4];
if (__jarOffset < 0 || __b == null || __o < 0 || __l < 0 ||
__o + __l > __b.length)
throw new SpringMLECallError("Invalid parameters.");
// Check to see if it is supported...
RawVMClassLibrary lib = MLEJarPackage.__rawLibrary(
__jar.library());
if (lib == null)
return -1;
// Otherwise request it
try
{
lib.rawData(__jarOffset, __b, __o, __l);
return __l;
}
catch (Throwable __t)
{
__t.printStackTrace();
return -1;
}
}
},
/** {@link JarPackageShelf#rawSize(JarPackageBracket)}. */
RAW_SIZE("rawSize:" +
"(Lcc/squirreljme/jvm/mle/brackets/JarPackageBracket;)I")
{
/**
* {@inheritDoc}
* @since 2022/03/05
*/
@Override
public Object handle(SpringThreadWorker __thread, Object... __args)
{
if (__args[0] == null)
throw new SpringMLECallError("No JAR specified.");
// Determine the path to the JAR
JarPackageObject jar = MLEJarPackage.__jarObject(__args[0]);
// Check to see if it is supported...
RawVMClassLibrary lib = MLEJarPackage.__rawLibrary(jar.library());
if (lib == null)
return -1;
// Otherwise request it
try
{
return lib.rawSize();
}
catch (Throwable __t)
{
__t.printStackTrace();
return -1;
}
}
},
/* End. */
;
/** The dispatch key. */
protected final String key;
/**
* Initializes the dispatcher info.
*
* @param __key The key.
* @throws NullPointerException On null arguments.
* @since 2020/06/18
*/
MLEJarPackage(String __key)
throws NullPointerException
{
if (__key == null)
throw new NullPointerException("NARG");
this.key = __key;
}
/**
* {@inheritDoc}
* @since 2020/06/18
*/
@Override
public String key()
{
return this.key;
}
/**
* Checks if this is a {@link JarPackageObject}.
*
* @param __object The object to check.
* @return As a jar if this is one.
* @throws SpringMLECallError If this is not a jar.
* @since 2020/06/22
*/
static JarPackageObject __jarObject(Object __object)
throws SpringMLECallError
{
if (!(__object instanceof JarPackageObject))
throw new SpringMLECallError("Not a JarPackageObject.");
return (JarPackageObject)__object;
}
/**
* Obtains the raw library.
*
* @param __lib The library to get the raw library of.
* @return The resultant library or {@code null} if there is none.
* @throws SpringMLECallError On null arguments.
* @since 2024/03/05
*/
static RawVMClassLibrary __rawLibrary(VMClassLibrary __lib)
throws SpringMLECallError
{
if (__lib == null)
throw new SpringMLECallError("Null arguments.");
// If an overlay, go deeper
if (__lib instanceof OverlayVMClassLibrary)
return MLEJarPackage.__rawLibrary(
((OverlayVMClassLibrary)__lib).originalLibrary());
// Is this a raw library?
if (__lib instanceof RawVMClassLibrary)
return (RawVMClassLibrary)__lib;
return null;
}
}