// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.gui.hexview;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import org.infinity.resource.key.ResourceEntry;
import tv.porst.jhexview.DataChangedEvent;
import tv.porst.jhexview.IDataChangedListener;
import tv.porst.jhexview.IDataProvider;
/**
* Provides data as byte array from the associated ResourceEntry instance to be used in
* JHexView components.
*/
public class ResourceDataProvider implements IDataProvider
{
private final ArrayList<IDataChangedListener> listeners = new ArrayList<IDataChangedListener>();
private final HashMap<Integer, Byte> modifiedMap = new HashMap<Integer, Byte>();
private final ResourceEntry entry;
private int size;
public ResourceDataProvider(ResourceEntry entry)
{
if (entry == null) {
throw new NullPointerException("entry is null");
}
this.entry = entry;
size = -1; // initialized when needed
}
//--------------------- Begin Interface IDataProvider ---------------------
@Override
public void addListener(IDataChangedListener listener)
{
if (listener != null && listeners.indexOf(listener) < 0) {
listeners.add(listener);
}
}
@Override
public byte[] getData(long offset, int length)
{
if (offset+length > getDataLength()) {
length = getDataLength() - (int)offset;
}
if (length > 0) {
try {
ByteBuffer bb = getResourceEntry().getResourceBuffer();
byte[] retVal = new byte[length];
for (int i = 0; i < length; i++) {
if (isModifiedData((int)offset+i)) {
retVal[i] = getModifiedData((int)offset+i);
} else {
retVal[i] = bb.get((int)offset+i);
}
}
return retVal;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
public int getDataLength()
{
if (size < 0) {
size = 0;
try {
long resSize = getResourceEntry().getResourceSize();
if (resSize >= 0) {
size = (int)resSize;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return size;
}
@Override
public boolean hasData(long start, int length)
{
return (start >= 0 && start+length <= getDataLength());
}
@Override
public boolean isEditable()
{
// to be fully implemented
return true;
}
@Override
public boolean keepTrying()
{
return false;
}
@Override
public void removeListener(IDataChangedListener listener)
{
if (listener != null) {
listeners.remove(listener);
}
}
@Override
public void setData(long offset, byte[] data)
{
if (data != null) {
for (int i = 0; i < data.length; i++) {
addModifiedData((int)offset, data[i]);
}
if (data.length > 0) {
fireDataChanged();
}
}
}
//--------------------- End Interface IDataProvider ---------------------
/** Returns the attached ResourceEntry instance. */
public ResourceEntry getResourceEntry()
{
return entry;
}
/** Removes all modified data information from the provider. */
public void clear()
{
clearModifiedData();
}
protected void fireDataChanged()
{
if (!listeners.isEmpty()) {
DataChangedEvent event = new DataChangedEvent(this);
for (int i = listeners.size()-1; i >= 0; i--) {
listeners.get(i).dataChanged(event);
}
}
}
private boolean isModifiedData(int offset)
{
return modifiedMap.containsKey(Integer.valueOf(offset));
}
private byte getModifiedData(int offset)
{
Byte b = modifiedMap.get(Integer.valueOf(offset));
if (b != null) {
return b.byteValue();
} else {
return 0;
}
}
private void addModifiedData(int offset, byte value)
{
if (offset >= 0 && offset < getDataLength()) {
modifiedMap.put(Integer.valueOf(offset), Byte.valueOf(value));
}
}
// private void removeModifiedData(int offset)
// {
// modifiedMap.remove(Integer.valueOf(offset));
// }
// Removes all modified data from the map.
private void clearModifiedData()
{
modifiedMap.clear();
}
}