The KVM source code includes an implementation for reading Java class files from regular files/directories, as well as from (compressed) JAR files. Generally speaking, the KVM class loader can be divided into two parts:
The generic part, defined in file VmCommon/src/loader.c
is designed to be independent of the file/storage system of the target device. This part of the class loader does not require any porting efforts. The JAR file reader, defined in files VmExtra/src/jar.c
, VmExtra/src/inflate.c
, VmExtra/h/jar.h
, VmExtra/h/inflate.h
, VmExtra/h/inflateint.h
, and VmExtra/h/inflatetables.h
, is also written in a way that it does not necessitate any porting efforts.
If you need to provide an alternative method for loading class files, you must define your own port-specific class loading mechanism. The default implementation in VmExtra/src/loaderFile.c
is intended for those target systems that have a conventional file system. This implementation can be used as a starting point for alternative, platform-specific implementations.
The KVM code to read JAR files can also be used independently of reading class files. Applications that need to make their own use of JAR files can use these functions. In addition, the function that decompresses compressed JAR entries (a process called “inflation”), can also be used to decompress other information. For example, the PNG image format uses the same compression and decompression algorithms.
The structures and functions required by the port-specific class file loading interface have been defined in file VmCommon/h/loader.h
. If you do not intend to use the default class file loading interface provided in file VmExtra/src/loaderFile.c
, you must supply your own definitions for the structures and functions listed below.
You must define the C structure filePointerStruct
. The generic code uses the definitions
without knowing anything about the fields of this structure.
You must also define the following functions:
void InitializeClassLoading()
The code typically initializes the variable ClassPathTable
and any other variables needed for file loading upon virtual machine startup. Keep in mind that the value in ClassPathTable
is usually a root for garbage collection, and must either be NULL
or be an object allocated from the heap.PATH_SEPARATOR
indicates the character that separates directories in the class path. Its default value is ':'
. If you are using Windows or a similar implementation, you will need to change this value to ';'
. (Defined in VmCommon/h/loader.h
.)void FinalizeClassLoading()
This function is the opposite of initializeClassLoading()
. This function performs the class loader finalization operations that are necessary when the virtual machine shuts down. Actual implementation will vary substantially depending on the target architecture.FILEPOINTER openClassfile(INSTANCE_CLASS clazz)
Open the class file pointed to by the clazz
pointer. void closeClassfile(FILEPOINTER_HANDLE ClassFileH)
Close the indicated class file. Close any system resources (such as file handles or database records) associated with the class file.void loadByteNoEOFCheck(FILEPOINTER_HANDLE ClassFileH)
Load the next byte if it is a JAR file, or load the next character and return it, or EOF (-1) if end of file was reached.unsigned char loadByte(FILEPOINTER_HANDLE ClassFileH)
unsigned short loadShort(FILEPOINTER_HANDLE ClassFileH)
unsigned long loadCell(FILEPOINTER_HANDLE ClassFileH)
Read the next one, two, or four bytes from the class file, and return the result as an unsigned 8-bit, unsigned 16-bit, or unsigned 32-bit value. 16- and 32-bit quantities in Java class files are always in big-endian format.void loadBytes(FILEPOINTER_HANDLE ClassFileH, char *buffer,
int len)
Load the next len
bytes from the class file into the indicated buffer.int loadBytesNoEOFCheck(FILEPOINTER_HANDLE ClassFileH,
char *buffer, int pos, int length)
Load the next length
bytes from the class file into the indicated buffer, but without checking for EOF.void skipBytes(FILEPOINTER_HANDLE ClassFileH,
unsigned long length)
length
bytes in the class file.int getBytesAvailable(FILEPOINTER_HANDLE ClassFileH)
Get the number of remaining bytes in the class file.
The class file structure returned by openClassFile
must be an object allocated from the Java heap.
CLDC-compliant KVM implementations are required to be able to read class files from compressed JAR files. The location of the JAR file(s) is specified in an implementation-dependent manner.
Functions are provided in jar.c
for reading entries in a JAR file. If the preprocessor symbol JAR_FILE_USE_STDIO
is non-zero, then these functions use C standard I/O routines to read the JAR file. If this preprocessor symbol is set to 0
, this indicates that JAR files are in memory.
The JAR file reader uses the inflater, which is discussed in the next section.
Before using a JAR file, you must “open” it using the function
The arguments are as follows:
If JAR_FILE_USE_STDIO
is non-zero, then the first argument is the name of the JAR file and the second argument is ignored.
If JAR_FILE_USE_STDIO
is zero, then the first argument is a pointer in memory to the beginning of the JAR file, and the second argument is the length, in bytes, of the JAR file.
The third argument is a pointer to a structure of type struct jarInfoStruct
defined in jar.h
. This structure is filled with information about the opened JAR file. This function returns TRUE
if it successfully managed to open the JAR file and parse its directory; it returns FALSE
otherwise.
If a JAR file has been successfully opened using openJARFile
, you must close the file when you are done. You must use the function:
The argument is a pointer to the same structure that was filled in by openJARFile
.
To read a specific entry in a JAR file, you use the function
static void * loadJARFileEntryInternal(JAR_INFO entry, const unsigned char *centralInfo, long *lengthP, int extraBytes);
The entry
argument is a pointer to the structure filled in by openJARFile
. The centralInfo
argument is the null-terminated name of the entry.1 The extraBytes
entry indicates that the JAR reader should pad the result with that many extra bytes at the beginning.
If the JAR file reader is successful, it will set the *lengthP
argument to the length of JAR file entry. This length does not include padding inserted because of the extraBytes
argument. The actual entry (plus padding) is returned as the result of this function.
If the JAR file reader could not find the entry, or if for some reason it was unable to read the entry, this function returns NULL
.
The result of this function is a heap-allocated object. If this function is called from within the KVM, then you must protect it, if necessary, from garbage collection.
To read the directory of a JAR file and possibly some of its entries, use the function
void loadJARFileEntries(JAR_INFO jarFile, JARFileTestFunction testFunction, JARFileRunFunction runFunction, void* info);
The jarFile
argument is a pointer to the structure filled in by openJARFile
. The testFunction
and runFunction
arguments are callback functions whose use is described below. The info
argument is not used by the jar directory reader, but is passed on an argument to the testFunction
and runFunction
callbacks.
The testFunction
argument is a callback function that is called on each (non-directory) entry in the JAR file. It is called as follows:
typedef bool_t (*JARFileTestFunction)(const char *name, int nameLength, int *extraBytes, void *info);
The name
and nameLength
argument specify the name of entry in the JAR file directory. The name
argument is not null terminated. The value *extraBytes
is initially zero, but you can change it to a different value to indicate that the result needs to be padded with extra bytes at the beginning. The info
argument is the same as whatever was passed to loadJARFileEntries
.
If this function returns TRUE
, it indicates that you want to read this entry. If this function returns FALSE
, you do not want to read this entry.
For every entry in which testFunction
returns TRUE
, the jar file reader reads the data and calls the runFunction
as follows:
typedef void (*JARFileRunFunction)(const char *name, int nameLength, void *value, long length, void *info);
The name
and nameLength
arguments are the same as above. The value
argument gives the result of reading the JAR file entry. The length
argument is the length of the JAR file entry, not including any padding bytes. The info
argument is the same as whatever was passed to loadJARFileEntries
.
If reading the entry is unsuccessful, then the runFunction
is called with the value
argument set to NULL
.
The value
argument is allocated on the heap so it must be protected, if necessary, from garbage collection.
The inflate function can be used to decompress streams that have been compressed using the so-called deflation algorithm. This is the compression algorithm commonly used in JAR files and in the PNG image format.
The function that inflates JAR file entries can also be used for other purposes. The function is called with the following arguments.
typedef int (*JarGetByteFunctionType)(void *); bool_t inflateData(void *compData, JarGetByteFunctionType getByte, int compLen, UNSIGNED_CHAR_HANDLE decompData, int decompLen);
This function decompresses a stream of compLen
bytes into a buffer of decompLen
bytes. Successive bytes of input are obtained by repeatedly calling
This function will be called up to compLen + INFLATER_EXTRA_BYTES
times, where INFLATER_EXTRA_BYTES
is defined in inflate.h
to be the constant 4. Any values returned beyond the first compLen
calls to the function are immaterial.
The argument decompData
must be a pointer to a buffer handle of at least decompLen
characters. When using this function, the buffer must either not be in the heap, or decompData
must be registered with the garbage collector so that decompData
is updated if the buffer is moved.
This function returns TRUE
if the decompression is successful, and FALSE
otherwise.
KVM Porting Guide , CLDC 1.1 |
Copyright © 2003 Sun Microsystems, Inc. All rights reserved.