FileDocCategorySizeDatePackage
AppResourceBundleReader.javaAPI DocphoneME MR2 API (J2ME)19788Wed May 02 18:00:46 BST 2007com.sun.j2me.global

AppResourceBundleReader

public class AppResourceBundleReader extends Object implements ResourceBundleReader
An instance of this class can be used for accessing application resource files.

Fields Summary
private static final String
classname
Class name
protected byte[]
supportedVersions
Array of resource file versions supported by this reader.
protected long
LASTRESOURCE_ID
ID of the last entry in the offset table.
protected byte
LASTRESOURCE_TYPE
Type of the last entry in the offset table.
protected String
resourceName
The name of resource.
protected Header
header
The binary resource file header.
protected InputStream
istream
The stream to read resource.
Constructors Summary
protected AppResourceBundleReader()
Creates new instance of AppResourceBundle. Always use {@link #getInstance} method.

 
Methods Summary
protected voidfreeResourceBundle()
Closes resource bundle.

throws
IOException if istream.close is unsuccessful.

    	try {
    		istream.close();
    	} catch (IOException ioe){
            if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                Logging.report(Logging.WARNING, LogChannels.LC_JSR238,
                               classname + "Exception while closing resource stream: "
                               + ioe.toString());
            }
    	}
    
public static ResourceBundleReadergetInstance(java.lang.String name)
Creates initialized instance of ResourceBundleReader It opens resource bundle and reads up header.

return
An initialized instance of ResourceBundleReader, null if resource bundle can't be read.
param
name path to resource bundle



                                                
         
        AppResourceBundleReader appreader = new AppResourceBundleReader();
        if (!appreader.initialize(name)) {
            return null;
        }
        return appreader;
    
public synchronized byte[]getRawResourceData(int resourceID)
Get raw binary data for resource id.

param
resourceID the resource identifier
return
resource as array of bytes or null if resource wasn't found.


        try {
            int length = header.getResourceLength(resourceID);
            if (length < 0) {
                throw new ResourceException(ResourceException.DATA_ERROR,
                        "Invalid resource length " + length);
            }
            byte[] buffer = new byte[length];
            if (length > 0){
                moveStreamTo(resourceID);
                int pos = 0;
                while (length > 0){
                	int bytesRead = istream.read(buffer,pos,length);
                	if (pos < 0){
                		throw new ResourceException(ResourceException.DATA_ERROR,
                                            "End of file.");
                	}
                	pos +=  bytesRead;
                	length -= bytesRead;
                }
            	freeResourceBundle();
           	}
            return buffer;

        } catch (IOException ioe) {
            throw new ResourceException(ResourceException.DATA_ERROR,
                    ioe.getMessage());
        }
    
protected java.io.InputStreamgetResourceBundleAsStream()
Opens resource bundle and return its stream.

return
stream for reading resource bundle or null if stream can't be opened.

        return getClass().getResourceAsStream(resourceName);
    
public synchronized intgetResourceLength(int resourceID)
Method gets length of resource.

param
resourceID the resource id
return
resource length in bytes, or -1 if resource wasn't found.

        int lth = header.getResourceLength(resourceID);
        return lth;
    
public java.lang.StringgetResourceName()
Method returns name of resource file used by this reader.

return
resource file name

        return resourceName;
    
public synchronized bytegetResourceType(int resourceID)
Method finds out resource type.

param
resourceID the resource id
return
type code.255if resource wasn't found

        long entry = header.getEntry(resourceID);
        if (entry == 0) {
            throw new ResourceException(ResourceException.RESOURCE_NOT_FOUND,
                                        "Cannot get resource type");
        }
        // flag that resource wasn't found
        byte type = header.getResourceType(entry);
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR238,
                           classname + ": resource type is " + type);
        }
        return type;
    
protected booleaninitialize(java.lang.String name)
Creates a new instance of AppResourceBundleReader.

param
name path to resource bundle
return
true if header was initialized

        resourceName = name;
        header = readHeader();
        return (header != null);
    
public synchronized booleanisValidResourceID(int resourceID)
Method checks if given resource id was valid.

param
resourceID the resource id
return
true if resource id was found in header.

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR238,
                           classname + ": validating resourceId=" + resourceID);
        }
        int index = header.getEntryIndex(resourceID);
        return (index >= 0);
    
protected synchronized voidmoveStreamTo(int resourceID)
Method moves stream into position of given resource.

param
resourceID the resource id

        try {
            long entry = header.getEntry(resourceID);
            if (entry == 0) {
                throw new ResourceException(
                          ResourceException.RESOURCE_NOT_FOUND, 
                          "Can't find resource \"" + resourceID + "\""); 
            }
            int offset = header.getResourceOffset(entry);
            // reopen stream
            freeResourceBundle();
            istream = getResourceBundleAsStream();
            // move to resource position
            long skipped=istream.skip(offset);
            if (skipped!=offset){
                throw new ResourceException(ResourceException.DATA_ERROR,
                        "Invalid offset of resource " + resourceID);
            }
        } catch (IOException ioe) {
            throw new ResourceException(ResourceException.DATA_ERROR,
                    ioe.getMessage());
        }
    
protected com.sun.j2me.global.AppResourceBundleReader$HeaderreadHeader()
Reads header of resource file.

return
initialized {@link Header}
throws
ResourceException if bundle file version is invalid.


        try {
            Header header = new Header();
            istream = getResourceBundleAsStream();
            if (istream == null) {
                throw new ResourceException(
                        ResourceException.NO_RESOURCES_FOR_BASE_NAME,
                        "Resource file not found.");
                // bundle can't be read
            }
            
            istream.read(header.getSignature());
            if (!header.isSignatureValid()) {
                throw new ResourceException(ResourceException.DATA_ERROR,
                        "Invalid resource file.");
            }
            int headerLength = readInt(istream);
            if ((headerLength <= 0) || ((headerLength & 0x7) != 0)){
                throw new ResourceException(ResourceException.DATA_ERROR,
                "Invalid resource file.");
            }
            int entriesCount = headerLength >> 3; // /8

            long[] entries;
            /* Check if the entriesCount is too large */
            try {
                entries = new long[entriesCount];
            } catch (OutOfMemoryError e) {
                throw new ResourceException(ResourceException.DATA_ERROR,
                                            "Out of memory.");
            }
            
            int prevID = -1;
            int prevOffset = headerLength + 8;
            for (int i = 0; i < entriesCount; ++i) {
            	entries[i] = readLong(istream);

                int id = header.getResourceId(entries[i]);
                int type = header.getResourceType(entries[i]);
                
                if (i == (entriesCount-1)) {
                	// terminator resource
	                if (id != LASTRESOURCE_ID){
	                    throw new ResourceException(ResourceException.DATA_ERROR,
	                            "Last entry should have ID " + LASTRESOURCE_ID + " but found ID " + id);
	                }
	                if (type != LASTRESOURCE_TYPE){
	                    throw new ResourceException(ResourceException.WRONG_RESOURCE_TYPE,
	                            "Last entry shoud have type " + LASTRESOURCE_TYPE + " but found type " + type);
	                }
	            }  else {
	                if (id<0){
	                    throw new ResourceException(ResourceException.DATA_ERROR,
	                    "Negative resource ID " + id);
	                }
	                if (id==prevID){
	                    throw new ResourceException(ResourceException.DATA_ERROR,
	                            "Duplicated id: " + id);
	                }
	                if (id<prevID){
	                    throw new ResourceException(ResourceException.DATA_ERROR,
	                            "Resources are not in ascending order: " + prevID + "," + id);
	                }
	                prevID = id;
	                
	                if (type == LASTRESOURCE_TYPE){
	                    throw new ResourceException(ResourceException.WRONG_RESOURCE_TYPE,
	                            "Only last entry can have type " + LASTRESOURCE_TYPE);
	                }
	            }
                
                int offset = header.getResourceOffset(entries[i]);
                
                if (offset < prevOffset) {
                    throw new ResourceException(ResourceException.DATA_ERROR,
                            "Invalid resource offset: " + id);
                }
                
                prevOffset = offset;
            }
            long dataLength = prevOffset - headerLength - 8;
            if (dataLength!=istream.skip(dataLength)){
                throw new ResourceException(ResourceException.DATA_ERROR,
                        "Resource file too short");
            }
            header.setEntries(entries);
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
	            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR238,
	                    classname + " Found "+ entries.length + " resource enries in " + resourceName);
            }
            freeResourceBundle();
            return header;
        } catch (IOException ioe) {
            throw new ResourceException(ResourceException.DATA_ERROR,
                    ioe.getMessage());
        } 
    
protected final intreadInt(java.io.InputStream in)
Read integer from resource bundle stream.

param
in resource bundle input stream
return
integer read from resource bundle
throws
IOException if error occured while reading

        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0) {
            throw new EOFException();
        }
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    
protected final longreadLong(java.io.InputStream in)
Read long from resource bundle stream.

param
in resource bundle input stream
return
integer read from resource bundle
throws
IOException if error occured while reading

    	long result=0;
    	for (int j = 0; j < 8; ++j) {
			int i = in.read();
			if (i < 0) {
				throw new EOFException();
			}
			result <<= 8;
			result += (long)(i & 0xFF);
		}
    	return result;