/*
* @(#)Resource.java 1.3 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.media.util;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.io.*;
import javax.media.format.*;
import javax.media.*;
import java.lang.*;
import java.util.*;
import com.sun.media.JMFSecurity;
import com.sun.media.IESecurity;
import com.sun.media.JMFSecurityManager;
import com.ms.security.PermissionID;
import com.ms.security.PolicyEngine;
/**
* Class where objects can be registered with a unique key (string).
* The Resource tries to find a ".jmf-resource" file in user.home.
* If it does, then it reads all the keys and corresponding objects.
* The resource file is generated and maintained solely by the MediaEngine.
* The structure of the serialized file is:
* Number of items in the table: integer
* Version number : integer
* Key for item 1 : UTF
* Value of item 1 : Object
* Key for item 2 : UTF
* Value of item 2 : Object
* and so on......
*/
public class Resource {
// Hashtable that stores all the properties.
private static Hashtable hash = null;
// Name of the properties file, including path.
private static String filename = null;
// Version number of the serialized file format. Will need
// to be incremented if the format changes so that an old
// implementation will expect errors with a new format.
private static final int versionNumber = 200;
private static boolean securityPrivelege=false;
private static JMFSecurity jmfSecurity = null;
private static Method m[] = new Method[1];
private static Class cl[] = new Class[1];
private static Object args[][] = new Object[1][0];
private static final String USERHOME = "user.home";
private static String userhome = null;
/**
* Static code block to read in the resource file and initialize
* the hash table.
*/
static {
hash = new Hashtable();
try {
jmfSecurity = JMFSecurityManager.getJMFSecurity();
securityPrivelege = true;
} catch (SecurityException e) {
}
if ( /* securityPrivelege && */ (jmfSecurity != null) ) {
String permission = null;
try {
if (jmfSecurity.getName().startsWith("jmf-security")) {
permission = "read property";
jmfSecurity.requestPermission(m, cl, args, JMFSecurity.READ_PROPERTY);
m[0].invoke(cl[0], args[0]);
permission = "read file";
jmfSecurity.requestPermission(m, cl, args, JMFSecurity.READ_FILE);
m[0].invoke(cl[0], args[0]);
} else if (jmfSecurity.getName().startsWith("internet")) {
PolicyEngine.checkPermission(PermissionID.PROPERTY);
PolicyEngine.checkPermission(PermissionID.FILEIO);
PolicyEngine.assertPermission(PermissionID.PROPERTY);
PolicyEngine.assertPermission(PermissionID.FILEIO);
}
} catch (Throwable e) {
if (JMFSecurityManager.DEBUG) {
System.err.println("Resource: Unable to get " + permission +
" privilege " + e.getMessage());
}
securityPrivelege = false;
}
}
if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) {
try {
Constructor cons = jdk12PropertyAction.cons;
userhome = (String) jdk12.doPrivM.invoke(
jdk12.ac,
new Object[] {
cons.newInstance(
new Object[] {
USERHOME,
})});
} catch (Throwable e) {
securityPrivelege = false;
}
} else {
try {
if (securityPrivelege)
userhome = System.getProperty(USERHOME);
} catch (Exception e) {
userhome = null;
securityPrivelege = false;
}
}
if (userhome == null) {
securityPrivelege = false;
}
InputStream is = null;
if (securityPrivelege) {
is = findResourceFile();
if (is == null) {
securityPrivelege=false; // there is no access to jmf.properties
}
}
if (!readResource(is)) {
hash = new Hashtable();
}
}
public static final synchronized void reset() {
hash = new Hashtable();
}
/**
* Add or modify a property. The key and the value should be non-null.
* Returns false if it couldn't add/modify the property.
*/
public static final synchronized boolean set(String key, Object value) {
if (key != null && value != null) {
if (jmfSecurity != null && key.indexOf("secure.") == 0)
return false;
hash.put(key, value);
return true;
} else
return false;
}
/**
* Returns the value corresponding to the specified key. Returns null
* if no such property is found.
*/
public static final synchronized Object get(String key) {
if (key != null)
return hash.get(key);
else
return null;
}
/**
* Removes a property from the hashtable. Returns false
* if the property was not found.
*/
public static final synchronized boolean remove(String key) {
if (key != null) {
if (hash.containsKey(key)) {
hash.remove(key);
return true;
}
}
return false;
}
/**
* Removes an entire set of properties with the keys starting with
* the value "keyStart".
*/
public static final synchronized void removeGroup(String keyStart) {
Vector keys = new Vector();
if (keyStart != null) {
Enumeration e = hash.keys();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
if (key.startsWith(keyStart))
keys.addElement(key);
}
}
for (int i = 0; i < keys.size(); i++) {
hash.remove(keys.elementAt(i));
}
}
/**
* Writes all the properties in the hashtable to the
* jmf.properties file. If the file is non-existent or the writing
* failed for some reason, it throws an IOException.
*/
public static final synchronized boolean commit()
throws IOException {
if (filename == null)
throw new IOException("Can't find resource file");
FileOutputStream fos = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(fos);
int tableSize = hash.size();
oos.writeInt(tableSize);
oos.writeInt(versionNumber);
for (Enumeration e = hash.keys(); e.hasMoreElements() ;) {
String key = (String) e.nextElement();
Object value = hash.get(key);
oos.writeUTF(key); // write key as UTF chars.
/*
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream tempOOS = new ObjectOutputStream(baos);
tempOOS.writeObject(value);
tempOOS.flush();
byte [] serObject = baos.toByteArray();
oos.writeObject(serObject);
tempOOS.close();
*/
oos.writeObject(value);
oos.flush();
}
oos.close();
return true;
}
/**
* Remove the permanent registry.
*/
public static final synchronized void destroy() {
if (filename == null)
return;
try {
File file = new File(filename);
file.delete();
} catch (Throwable t) {
filename = null;
}
}
private static final synchronized InputStream findResourceFile() {
String dir;
String strJMF = ".jmf-resource";
File file = null;
InputStream ris = null;
if (userhome == null)
return null;
try {
filename = userhome + File.separator + strJMF;
//System.out.println("Resource: file name is " + filename);
file = new File(filename);
ris = getResourceStream(file);
} catch (Throwable t) {
filename = null;
return null;
}
return ris;
}
private static final FileInputStream getResourceStream(File file) throws IOException {
try {
if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) {
Constructor cons = jdk12ReadFileAction.cons;
return (FileInputStream) jdk12.doPrivM.invoke(
jdk12.ac,
new Object[] {
cons.newInstance(
new Object[] {
file.getPath()
})});
} else {
if (!file.exists()) {
//System.out.println("file doesnt exist");
return null;
} else {
return new FileInputStream(file.getPath());
}
}
} catch (Throwable t) {
return null;
}
}
private static final synchronized boolean readResource(InputStream ris) {
if (ris == null)
return false;
try {
// Inner class with skipHeader so that the protected method
// readStreamHeader can be called.
ObjectInputStream ois = new ObjectInputStream(ris);
int tableSize = ois.readInt();
int version = ois.readInt();
if (version > 200) {
System.err.println("Version number mismatch.\nThere could be" +
" errors in reading the resource");
}
hash = new Hashtable();
for (int i = 0; i < tableSize; i++) {
String key = ois.readUTF();
boolean failed = false;
byte [] serObject;
try {
/*
serObject = (byte[])ois.readObject();
ByteArrayInputStream bais = new ByteArrayInputStream(serObject);
ObjectInputStream tois = new ObjectInputStream(bais);
Object value = tois.readObject();
hash.put(key, value);
tois.close();
*/
Object value = ois.readObject();
hash.put(key, value);
} catch (ClassNotFoundException cnfe) {
failed = true;
} catch (OptionalDataException ode) {
failed = true;
}
}
ois.close();
ris.close();
} catch (IOException ioe) {
System.err.println("IOException in readResource: " + ioe);
return false;
} catch (Throwable t) {
return false;
}
return true;
}
/////////////////////////////////////////////////////////
//
// Static methods to get/save supported formats
// to a runtime/static database. This is to speed up
// the runtime for TrackControl.getSupportedFormats()
/////////////////////////////////////////////////////////
// We have 3 sets of tables, one for audio formats, one for
// video formats, one for "other" formats. This will speed
// up the search a little.
static FormatTable audioFmtTbl;
static FormatTable videoFmtTbl;
static FormatTable miscFmtTbl;
static Object fmtTblSync = new Object();
static int AUDIO_TBL_SIZE = 40;
static int VIDEO_TBL_SIZE = 20;
static int MISC_TBL_SIZE = 10;
static String AUDIO_SIZE_KEY = "ATS";
static String AUDIO_INPUT_KEY = "AI.";
static String AUDIO_FORMAT_KEY = "AF.";
static String AUDIO_HIT_KEY = "AH.";
static String VIDEO_SIZE_KEY = "VTS";
static String VIDEO_INPUT_KEY = "VI.";
static String VIDEO_FORMAT_KEY = "VF.";
static String VIDEO_HIT_KEY = "VH.";
static String MISC_SIZE_KEY = "MTS";
static String MISC_INPUT_KEY = "MI.";
static String MISC_FORMAT_KEY = "MF.";
static String MISC_HIT_KEY = "MH.";
static boolean needSaving = false;
/**
* Initialize the supported format tables.
*/
static final void initDB() {
synchronized (fmtTblSync) {
audioFmtTbl = new FormatTable(AUDIO_TBL_SIZE);
videoFmtTbl = new FormatTable(VIDEO_TBL_SIZE);
miscFmtTbl = new FormatTable(MISC_TBL_SIZE);
loadDB();
}
}
/**
* Reset (destroy) the supported format tables.
*/
public static final void purgeDB() {
synchronized (fmtTblSync) {
if (audioFmtTbl == null)
return;
audioFmtTbl = new FormatTable(AUDIO_TBL_SIZE);
videoFmtTbl = new FormatTable(VIDEO_TBL_SIZE);
miscFmtTbl = new FormatTable(MISC_TBL_SIZE);
}
}
/**
* Given an input format, check the tables to for its supported
* formats.
*/
public static final Format[] getDB(Format input) {
synchronized (fmtTblSync) {
if (audioFmtTbl == null)
initDB();
if (input instanceof AudioFormat)
return audioFmtTbl.get(input);
else if (input instanceof VideoFormat)
return videoFmtTbl.get(input);
return miscFmtTbl.get(input);
}
}
/**
* Save an input format and it's supported formats to the table.
*/
public static final Format [] putDB(Format input, Format supported[]) {
synchronized (fmtTblSync) {
Format in = input.relax();
Format list[] = new Format[supported.length];
for (int i = 0; i < supported.length; i++)
list[i] = supported[i].relax();
if (in instanceof AudioFormat)
audioFmtTbl.save(in, list);
else if (in instanceof VideoFormat)
videoFmtTbl.save(in, list);
else
miscFmtTbl.save(in, list);
needSaving = true;
return list;
}
}
/**
* Load the supported format table from the resource file.
*/
private static final void loadDB() {
synchronized (fmtTblSync) {
int i, size;
Object key, value, hit;
key = Resource.get(AUDIO_SIZE_KEY);
if (key instanceof Integer)
size = ((Integer)key).intValue();
else
size = 0;
if (size > AUDIO_TBL_SIZE) {
// Something's wrong.
System.err.println("Resource file is corrupted");
size = AUDIO_TBL_SIZE;
}
//System.err.println("audio table size = " + size);
audioFmtTbl.last = size;
for (i = 0; i < size; i++) {
key = Resource.get(AUDIO_INPUT_KEY + i);
value = Resource.get(AUDIO_FORMAT_KEY + i);
hit = Resource.get(AUDIO_HIT_KEY + i);
if (key instanceof Format && value instanceof Format[] &&
hit instanceof Integer) {
audioFmtTbl.keys[i] = (Format)key;
audioFmtTbl.table[i] = (Format[])value;
audioFmtTbl.hits[i] = ((Integer)hit).intValue();
} else {
System.err.println("Resource file is corrupted");
audioFmtTbl.last = 0;
break;
}
}
key = Resource.get(VIDEO_SIZE_KEY);
if (key instanceof Integer)
size = ((Integer)key).intValue();
else
size = 0;
if (size > VIDEO_TBL_SIZE) {
// Something's wrong.
System.err.println("Resource file is corrupted");
size = VIDEO_TBL_SIZE;
}
//System.err.println("video table size = " + size);
videoFmtTbl.last = size;
for (i = 0; i < size; i++) {
key = Resource.get(VIDEO_INPUT_KEY + i);
value = Resource.get(VIDEO_FORMAT_KEY + i);
hit = Resource.get(VIDEO_HIT_KEY + i);
if (key instanceof Format && value instanceof Format[] &&
hit instanceof Integer) {
videoFmtTbl.keys[i] = (Format)key;
videoFmtTbl.table[i] = (Format[])value;
videoFmtTbl.hits[i] = ((Integer)hit).intValue();
} else {
System.err.println("Resource file is corrupted");
videoFmtTbl.last = 0;
break;
}
}
key = Resource.get(MISC_SIZE_KEY);
if (key instanceof Integer)
size = ((Integer)key).intValue();
else
size = 0;
if (size > MISC_TBL_SIZE) {
// Something's wrong.
System.err.println("Resource file is corrupted");
size = MISC_TBL_SIZE;
}
//System.err.println("misc table size = " + size);
miscFmtTbl.last = size;
for (i = 0; i < size; i++) {
key = Resource.get(MISC_INPUT_KEY + i);
value = Resource.get(MISC_FORMAT_KEY + i);
hit = Resource.get(MISC_HIT_KEY + i);
if (key instanceof Format && value instanceof Format[] &&
hit instanceof Integer) {
miscFmtTbl.keys[i] = (Format)key;
miscFmtTbl.table[i] = (Format[])value;
miscFmtTbl.hits[i] = ((Integer)hit).intValue();
} else {
System.err.println("Resource file is corrupted");
miscFmtTbl.last = 0;
break;
}
}
} // synchronized
}
/**
* Save the table of supported formats to the resource file.
*/
public static final void saveDB() {
synchronized (fmtTblSync) {
if (!needSaving)
return;
Resource.reset();
int i;
Resource.set(AUDIO_SIZE_KEY, new Integer(audioFmtTbl.last));
for (i = 0; i < audioFmtTbl.last; i++) {
Resource.set(AUDIO_INPUT_KEY + i, audioFmtTbl.keys[i]);
Resource.set(AUDIO_FORMAT_KEY + i, audioFmtTbl.table[i]);
Resource.set(AUDIO_HIT_KEY + i, new Integer(audioFmtTbl.hits[i]));
}
Resource.set(VIDEO_SIZE_KEY, new Integer(videoFmtTbl.last));
for (i = 0; i < videoFmtTbl.last; i++) {
Resource.set(VIDEO_INPUT_KEY + i, videoFmtTbl.keys[i]);
Resource.set(VIDEO_FORMAT_KEY + i, videoFmtTbl.table[i]);
Resource.set(VIDEO_HIT_KEY + i, new Integer(videoFmtTbl.hits[i]));
}
Resource.set(MISC_SIZE_KEY, new Integer(miscFmtTbl.last));
for (i = 0; i < miscFmtTbl.last; i++) {
Resource.set(MISC_INPUT_KEY + i, miscFmtTbl.keys[i]);
Resource.set(MISC_FORMAT_KEY + i, miscFmtTbl.table[i]);
Resource.set(MISC_HIT_KEY + i, new Integer(miscFmtTbl.hits[i]));
}
try {
Resource.commit();
} catch (Throwable e) {
//System.err.println("Cannot save resource file: " + e);
}
needSaving = false;
} // synchronized
}
}
/**
* This is a utility class to store supported formats in a table.
* This cannot be an internal class since it has to be used in
* static methods.
*/
class FormatTable {
public Format keys[];
public Format table[][];
public int hits[];
public int last;
public FormatTable(int size) {
keys = new Format[size];
table = new Format[size][];
hits = new int[size];
last = 0;
}
/**
* Given an input format, check the tables to for its supported formats.
*/
Format[] get(Format input) {
Format res[] = null;
for (int i = 0; i < last; i++) {
if (res == null && keys[i].matches(input)) {
res = table[i];
hits[i] = keys.length;
//System.err.println("found match");
} else
hits[i] = hits[i] - 1;
}
return res;
}
/**
* Save the supported formats with a input key to the table.
*/
public void save(Format input, Format supported[]) {
int idx;
if (last >= keys.length) {
idx = findLeastHit();
} else {
idx = last;
last++;
}
keys[idx] = input;
table[idx] = supported;
hits[idx] = keys.length;
}
/**
* Find the least used entry in the table.
*/
public int findLeastHit() {
int min = hits[0];
int idx = 0;
for (int i = 1; i < last; i++) {
if (hits[i] < min) {
min = hits[i];
idx = i;
}
}
return idx;
}
}
|