/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.rms;
import java.io.*;
import java.util.*;
import malik.emulator.io.cloud.*;
import malik.emulator.io.vfs.*;
public class RecordStore extends Object
{
public static final int AUTHMODE_PRIVATE = 0;
public static final int AUTHMODE_ANY = 1;
public static final int STATE_ERROR = -1;
public static final int STATE_RESERV = 0;
public static final int STATE_OPENED = 1;
public static final int STATE_CLOSED = 2;
private static int COUNT;
private static RecordStore[] OPENED;
private static final char RMS_HEX_PREFIX = '$';
private static final int RMS_MAX_LENGTH = 32;
private static final long RMS_SIGNATURE = 0x6d6964702d726d73L;
private static final String RMS_DIRECTORY = "/rms/";
private static final String RMS_EXTENSION = ".rms";
private static final RecordFilter DEFAULT_FILTER;
private static final RecordComparator DEFAULT_COMPARATOR;
private static final Object LOCK;
static
{
DefaultFilterAndComparator obj = new DefaultFilterAndComparator();
DEFAULT_FILTER = obj;
DEFAULT_COMPARATOR = obj;
LOCK = obj;
}
public static void closeAllRecordStores()
{
int i;
RecordStore store;
synchronized(LOCK)
{
for(i = COUNT; i-- > 0; )
{
if((store = OPENED[i]) != null && store.openedCount != 0)
{
if(!store.saveData())
{
System.err.println("RecordStore.closeRecordStore: " +
"не удалось сохранить данные.");
}
store.openedCount = 0;
store.count = 0;
store.records = null;
store.listeners = null;
System.out.println("RecordStore: внесены изменения в запись ".concat(
store.recordStoreName));
}
}
}
}
public static void deleteRecordStore(String recordStoreName)
throws RecordStoreException, RecordStoreNotFoundException
{
int i;
int error;
checkName(recordStoreName);
error = 0;
synchronized(LOCK)
{
label0:
{
if((i = indexOfRecordStore(recordStoreName)) >= 0)
{
if(OPENED[i].openedCount != 0)
{
error = 1;
break label0;
}
OPENED[i] = null;
}
}
}
if(error == 1)
{
throw new RecordStoreException("RecordStore.deleteRecordStore: " +
"невозможно удалить открытое хранилище записей " + recordStoreName + ".");
}
try
{
CloudFileSystem.getInstance().deleteFile(RMS_DIRECTORY +
toFileName(recordStoreName) + RMS_EXTENSION);
}
catch(IOException e)
{
throw new RecordStoreNotFoundException("RecordStore.deleteRecordStore: " +
"хранилище записей " + recordStoreName + " не найдено.");
}
}
public static int getState(String recordStoreName)
{
int i;
RecordStore store;
return recordStoreName == null ||
(i = recordStoreName.length()) < 1 || i > RMS_MAX_LENGTH ? STATE_ERROR :
((store = getRecordStore(recordStoreName)) == null ? STATE_RESERV :
(store.openedCount != 0 ? STATE_OPENED : STATE_CLOSED));
}
public static String[] listRecordStores()
{
int i;
int fnlen;
int extlen = RMS_EXTENSION.length();
String[] result;
String name;
Vector list = new Vector(COUNT);
RecordStore store;
FileEnumerator fe;
for(i = COUNT; i-- > 0; )
{
if((store = OPENED[i]) != null)
{
list.addElement(store.recordStoreName);
}
}
try
{
if((fe = CloudFileSystem.getInstance().findFirst(RMS_DIRECTORY)) != null)
{
try
{
do
{
if((!fe.isDirectory()) && (name = fe.getFileName()) != null &&
name.regionMatches(true, fnlen = name.length() - extlen,
RMS_EXTENSION, 0, extlen) && (!list.contains(name =
toRecordStoreName(name.substring(0, fnlen)))))
{
list.addElement(name);
}
} while(fe.findNext());
}
finally
{
fe.close();
}
}
}
catch(IOException e)
{
e.printRealStackTrace();
}
list.copyInto(result = new String[list.size()]);
return result;
}
public static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary)
throws RecordStoreException, RecordStoreNotFoundException, RecordStoreFullException
{
int i;
int error;
RecordStore result;
checkName(recordStoreName);
error = 0;
synchronized(LOCK)
{
label0:
{
if((i = indexOfRecordStore(recordStoreName)) >= 0)
{
if((i = (result = OPENED[i]).openedCount) == 0 &&
(!result.loadData()) && (!createIfNecessary))
{
error = 1;
break label0;
}
result.openedCount = i + 1;
} else
{
if((!(result = new RecordStore(recordStoreName)).loadData()) &&
(!createIfNecessary))
{
error = 2;
break label0;
}
register(result);
result.openedCount = 1;
}
}
}
switch(error)
{
case 1:
throw new RecordStoreException("RecordStore.openRecordStore: " +
"не удалось загрузить данные.");
case 2:
throw new RecordStoreNotFoundException("RecordStore.openRecordStore: " +
"не удалось найти хранилище записей " + recordStoreName + ".");
}
return result;
}
public static RecordStore openRecordStore(String recordStoreName,
boolean createIfNecessary, int authmode, boolean writable)
throws RecordStoreException, RecordStoreNotFoundException, RecordStoreFullException
{
return openRecordStore(recordStoreName, createIfNecessary);
}
public static RecordStore openRecordStore(String recordStoreName, String vendor, String suite)
throws RecordStoreException, RecordStoreNotFoundException
{
return openRecordStore(recordStoreName, false);
}
static Object getMonitor()
{
return LOCK;
}
private static void checkName(String recordStoreName)
{
int len;
if(recordStoreName == null || (len = recordStoreName.length()) < 1 || len > RMS_MAX_LENGTH)
{
throw new IllegalArgumentException("RecordStore: " +
"недопустимое имя для хранилища записей.");
}
}
private static void register(RecordStore store)
{
int i;
if(OPENED == null)
{
OPENED = new RecordStore[2];
}
for(i = COUNT; i-- > 0; )
{
if(OPENED[i] == null)
{
OPENED[i] = store;
return;
}
}
if(COUNT == OPENED.length)
{
Array.copy(OPENED, 0, OPENED = new RecordStore[COUNT << 1], 0, COUNT);
}
OPENED[COUNT++] = store;
}
private static char getDigitRepresentation(int digit)
{
if(digit >= 0x00 && digit < 0x0a)
{
return (char) (digit + '0');
}
if(digit >= 0x0a && digit < 0x10)
{
return (char) (digit + ('A' - 0x0a));
}
throw new ArrayIndexOutOfBoundsException(digit);
}
private static int indexOfRecordStore(String recordStoreName)
{
int i;
RecordStore store;
for(i = COUNT; i-- > 0; )
{
if((store = OPENED[i]) != null && recordStoreName.equals(store.recordStoreName))
{
return i;
}
}
return -1;
}
private static RecordStore getRecordStore(String recordStoreName)
{
int i;
RecordStore store;
for(i = COUNT; i-- > 0; )
{
if((store = OPENED[i]) != null && recordStoreName.equals(store.recordStoreName))
{
return store;
}
}
return null;
}
private static String toFileName(String recordStoreName)
{
char c;
int i;
int len = recordStoreName.length();
int length = 0;
char[] result = new char[5 * RMS_MAX_LENGTH];
for(i = 0; i < len; )
{
if(((c = recordStoreName.charAt(i++)) >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))
{
result[length++] = c;
continue;
}
result[length++] = RMS_HEX_PREFIX;
result[length++] = getDigitRepresentation((c >> 0x0c) & 0x0f);
result[length++] = getDigitRepresentation((c >> 0x08) & 0x0f);
result[length++] = getDigitRepresentation((c >> 0x04) & 0x0f);
result[length++] = getDigitRepresentation(c & 0x0f);
}
return new String(result, 0, length);
}
private static String toRecordStoreName(String fileName)
{
char c;
char d;
int i;
int j;
int len = fileName.length();
int length = 0;
char[] result = new char[RMS_MAX_LENGTH];
for(i = 0; i < len && length < RMS_MAX_LENGTH; )
{
if((c = fileName.charAt(i++)) == RMS_HEX_PREFIX)
{
c = 0;
j = 0;
do
{
if(i >= len)
{
break;
}
if((d = fileName.charAt(i++)) >= '0' && d <= '9')
{
c = (char) ((((int) c) << 4) + (d - '0'));
continue;
}
if(d >= 'A' && d <= 'F')
{
c = (char) ((((int) c) << 4) + (d - ('A' - 0x0a)));
continue;
}
break;
} while((++j) < 4);
}
result[length++] = c;
}
return new String(result, 0, length);
}
private int openedCount;
private int nextID;
private int version;
private int count;
private long lastModified;
private Record[] records;
private RecordListener[] listeners;
private String recordStoreName;
private String fileName;
private RecordStore(String recordStoreName)
{
this.recordStoreName = recordStoreName;
this.fileName = RMS_DIRECTORY + toFileName(recordStoreName) + RMS_EXTENSION;
}
public void addRecordListener(RecordListener listener)
{
int i;
RecordListener[] listeners;
if(listener == null)
{
return;
}
synchronized(LOCK)
{
if((listeners = this.listeners) == null)
{
listeners = this.listeners = new RecordListener[2];
}
if(indexOfListener(listener) < 0)
{
if((i = indexOfListener(null)) < 0)
{
Array.copy(listeners, 0, listeners = this.listeners =
new RecordListener[(i = listeners.length) << 1], 0, i);
}
listeners[i] = listener;
}
}
}
public void removeRecordListener(RecordListener listener)
{
int i;
RecordListener[] listeners;
if(listener == null)
{
return;
}
synchronized(LOCK)
{
if((listeners = this.listeners) != null && (i = indexOfListener(listener)) >= 0)
{
listeners[i] = null;
}
}
}
public void closeRecordStore()
throws RecordStoreException, RecordStoreNotOpenException
{
int i;
int error = 0;
synchronized(LOCK)
{
label0:
{
if((i = openedCount) == 0)
{
error = 1;
break label0;
}
if((openedCount = i - 1) == 0)
{
if(!saveData())
{
error = 2;
break label0;
}
count = 0;
records = null;
listeners = null;
System.out.println("RecordStore: внесены изменения в запись ".concat(
recordStoreName));
}
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.closeRecordStore: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new RecordStoreException("RecordStore.closeRecordStore: " +
"не удалось сохранить данные.");
}
}
public void setMode(int authmode, boolean writable)
throws RecordStoreException
{
if(authmode != AUTHMODE_ANY && authmode != AUTHMODE_PRIVATE)
{
throw new IllegalArgumentException("RecordStore.setMode: " +
"недопустимое значение параметра authmode.");
}
}
public void setRecord(int recordId, byte[] src, int offset, int length)
throws RecordStoreException, RecordStoreFullException,
RecordStoreNotOpenException, InvalidRecordIDException
{
int lim;
int len;
int index;
int error;
byte[] data;
if(src != null && ((lim = offset + length) > (len = src.length) ||
lim < offset || offset > len || offset < 0))
{
throw new ArrayIndexOutOfBoundsException("RecordStore.setRecord: " +
"индекс выходит из диапазона.");
}
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
break label0;
}
if((index = indexOfRecord(recordId)) < 0)
{
error = 2;
break label0;
}
if(src != null)
{
Array.copy(src, offset, data = new byte[length], 0, length);
} else
{
data = new byte[0];
}
records[index].setData(data);
version++;
lastModified = System.currentTimeMillis();
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.setRecord: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new InvalidRecordIDException("RecordStore.setRecord: " +
"несуществующий идентификатор записи: " + recordId + ".");
}
notifyListenersChanged(recordId);
}
public void deleteRecord(int recordId)
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int i;
int c;
int index;
int error;
Record[] r;
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
break label0;
}
if((index = indexOfRecord(recordId)) < 0)
{
error = 2;
break label0;
}
r = records;
if((i = (c = count - 1) - index) > 0)
{
Array.copy(r, index + 1, r, index, i);
}
r[count = c] = null;
version++;
lastModified = System.currentTimeMillis();
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.deleteRecord: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new InvalidRecordIDException("RecordStore.deleteRecord: " +
"несуществующий идентификатор записи: " + recordId + ".");
}
notifyListenersDeleted(recordId);
}
public int addRecord(byte[] src, int offset, int length)
throws RecordStoreException, RecordStoreNotOpenException, RecordStoreFullException
{
int c;
int lim;
int len;
int error;
int result;
byte[] data;
Record[] r;
if(src != null && ((lim = offset + length) > (len = src.length) ||
lim < offset || offset > len || offset < 0))
{
throw new ArrayIndexOutOfBoundsException("RecordStore.addRecord: " +
"индекс выходит из диапазона.");
}
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
result = 0;
break label0;
}
if((r = records) == null || r.length == 0)
{
r = records = new Record[1];
}
if((c = count) == r.length)
{
Array.copy(r, 0, r = records = new Record[c << 1], 0, c);
}
if(src != null)
{
Array.copy(src, offset, data = new byte[length], 0, length);
} else
{
data = new byte[0];
}
r[c] = new Record(result = nextID++, data);
count = c + 1;
version++;
lastModified = System.currentTimeMillis();
}
}
if(error == 1)
{
throw new RecordStoreNotOpenException("RecordStore.addRecord: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
notifyListenersAdded(result);
return result;
}
public int getRecord(int recordId, byte[] dst, int offset)
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int lim;
int len;
int index;
int error;
int length;
byte[] data;
if(dst == null)
{
throw new NullPointerException("RecordStore.getRecord: " +
"параметр dst равен нулевой ссылке.");
}
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
length = 0;
break label0;
}
if((index = indexOfRecord(recordId)) < 0)
{
error = 2;
length = 0;
break label0;
}
length = (data = records[index].getData()).length;
if((lim = offset + length) > (len = dst.length) ||
lim < offset || offset > len || offset < 0)
{
error = 3;
break label0;
}
Array.copy(data, 0, dst, offset, length);
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.getRecord: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new InvalidRecordIDException("RecordStore.getRecord: " +
"несуществующий идентификатор записи: " + recordId + ".");
case 3:
throw new ArrayIndexOutOfBoundsException("RecordStore.getRecord: " +
"индекс выходит из диапазона.");
}
return length;
}
public int getRecordSize(int recordId)
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int index;
int error;
int result;
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
result = 0;
break label0;
}
if((index = indexOfRecord(recordId)) < 0)
{
error = 2;
result = 0;
break label0;
}
result = records[index].getDataSize();
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.getRecordSize: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new InvalidRecordIDException("RecordStore.getRecordSize: " +
"несуществующий идентификатор записи: " + recordId + ".");
}
return result;
}
public int getSizeAvailable()
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getSizeAvailable: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return (int) Runtime.getRuntime().freeMemory();
}
public int getSize()
throws RecordStoreNotOpenException
{
int i;
int error;
int result;
Record[] r;
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
result = 0;
break label0;
}
result = 0x20;
for(r = records, i = count; i-- > 0; )
{
if(((result += r[i].getDataSize() + 0x08) & 0x03) != 0)
{
result = (result + 0x04) & (-0x04);
}
}
}
}
if(error == 1)
{
throw new RecordStoreNotOpenException("RecordStore.getSize: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return result;
}
public int getVersion()
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getVersion: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return version;
}
public int getNumRecords()
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getNumRecords: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return count;
}
public int getNextRecordID()
throws RecordStoreException, RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getNextRecordID: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return nextID;
}
public long getLastModified()
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getLastModified: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return lastModified;
}
public byte[] getRecord(int recordId)
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int index;
int error;
int length;
byte[] data;
byte[] result;
error = 0;
synchronized(LOCK)
{
label0:
{
if(openedCount == 0)
{
error = 1;
result = null;
break label0;
}
if((index = indexOfRecord(recordId)) < 0)
{
error = 2;
result = null;
break label0;
}
Array.copy(data = records[index].getData(), 0,
result = new byte[length = data.length], 0, length);
}
}
switch(error)
{
case 1:
throw new RecordStoreNotOpenException("RecordStore.getRecord: " +
"хранилище записей " + recordStoreName + " не открыто.");
case 2:
throw new InvalidRecordIDException("RecordStore.getRecord: " +
"несуществующий идентификатор записи: " + recordId + ".");
}
return result;
}
public String getName()
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.getName: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return recordStoreName;
}
public RecordEnumeration enumerateRecords(RecordFilter filter,
RecordComparator comparator, boolean autoRebuild)
throws RecordStoreNotOpenException
{
if(openedCount == 0)
{
throw new RecordStoreNotOpenException("RecordStore.enumerateRecords: " +
"хранилище записей " + recordStoreName + " не открыто.");
}
return new Enumerator(this, filter == null ? DEFAULT_FILTER : filter,
comparator == null ? DEFAULT_COMPARATOR : comparator, autoRebuild);
}
boolean isRecordStoreOpened()
{
return openedCount != 0;
}
int getRecordsCount()
{
return count;
}
Record[] getRecords()
{
return records;
}
String getRecordStoreName()
{
return recordStoreName;
}
private void notifyListenersAdded(int recordId)
{
int i;
RecordListener[] listeners;
RecordListener listener;
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) != null)
{
try
{
listener.recordAdded(this, recordId);
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
}
}
private void notifyListenersChanged(int recordId)
{
int i;
RecordListener[] listeners;
RecordListener listener;
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) != null)
{
try
{
listener.recordChanged(this, recordId);
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
}
}
private void notifyListenersDeleted(int recordId)
{
int i;
RecordListener[] listeners;
RecordListener listener;
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) != null)
{
try
{
listener.recordDeleted(this, recordId);
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
}
}
private boolean saveData()
{
boolean result;
int i;
int c;
int length;
byte[] data;
Record[] r;
Record rec;
FileOutputStream file;
DataOutputStream stream;
if((file = new FileOutputStream(fileName)).hasOpenError())
{
return false;
}
try
{
try
{
(stream = new DataOutputStream(file)).writeLong(RMS_SIGNATURE);
stream.writeInt(c = this.count);
stream.writeInt(this.version);
stream.writeLong(this.lastModified);
stream.writeInt(this.nextID);
stream.writeInt(0);
for(r = this.records, i = 0; i < c; i++)
{
stream.writeInt((rec = r[i]).getRecordID());
stream.writeInt(length = (data = rec.getData()).length);
stream.write(data);
switch(length & 0x03)
{
case 0x01:
stream.writeByte(0);
/* fall through */
case 0x02:
stream.writeByte(0);
/* fall through */
case 0x03:
stream.writeByte(0);
/* fall through */
default:
break;
}
}
}
finally
{
file.close();
}
result = true;
}
catch(IOException e)
{
e.printRealStackTrace();
result = false;
}
return result;
}
private boolean loadData()
{
boolean result;
int i;
int c;
int id;
int length;
byte[] data;
Record[] r;
FileInputStream file;
DataInputStream stream;
if((file = new FileInputStream(fileName)).hasOpenError())
{
this.nextID = 1;
this.version = 1;
this.count = 0;
this.lastModified = System.currentTimeMillis();
this.records = null;
return false;
}
try
{
try
{
if((stream = new DataInputStream(file)).readLong() != RMS_SIGNATURE)
{
this.nextID = 1;
this.version = 1;
this.count = 0;
this.lastModified = System.currentTimeMillis();
this.records = null;
result = false;
} else
{
this.count = c = stream.readInt();
this.version = stream.readInt();
this.lastModified = stream.readLong();
this.nextID = stream.readInt();
this.records = r = new Record[c];
for(stream.skipBytes(0x04), i = 0; i < c; i++)
{
id = stream.readInt();
stream.read(data = new byte[length = stream.readInt()]);
if((length &= 0x03) != 0)
{
stream.skipBytes(0x04 - length);
}
r[i] = new Record(id, data);
}
result = true;
}
}
finally
{
file.close();
}
}
catch(IOException e)
{
this.nextID = 1;
this.version = 1;
this.count = 0;
this.lastModified = System.currentTimeMillis();
this.records = null;
e.printRealStackTrace();
result = false;
}
return result;
}
private int indexOfRecord(int recordId)
{
int i;
Record[] r;
for(r = records, i = count; i-- > 0; )
{
if(r[i].getRecordID() == recordId)
{
return i;
}
}
return -1;
}
private int indexOfListener(RecordListener listener)
{
int i;
RecordListener[] listeners;
for(i = (listeners = this.listeners).length; i-- > 0; )
{
if(listeners[i] == listener)
{
return i;
}
}
return -1;
}
}