// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.resource.key;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Locale;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import org.infinity.NearInfinity;
import org.infinity.gui.BrowserMenuBar;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.are.AreResource;
import org.infinity.resource.cre.CreResource;
import org.infinity.resource.itm.ItmResource;
import org.infinity.resource.other.EffResource;
import org.infinity.resource.other.VvcResource;
import org.infinity.resource.pro.ProResource;
import org.infinity.resource.spl.SplResource;
import org.infinity.resource.sto.StoResource;
import org.infinity.search.SearchOptions;
import org.infinity.util.io.StreamUtils;
public abstract class ResourceEntry implements Comparable<ResourceEntry>
{
// list of file extensions not shown in the resource tree
private static final HashSet<String> skippedExtensions = new HashSet<String>();
static {
skippedExtensions.add("BAK");
skippedExtensions.add("BIF");
}
private String searchString;
static int[] getLocalFileInfo(Path file)
{
if (file != null && Files.isRegularFile(file)) {
try (SeekableByteChannel ch = Files.newByteChannel(file, StandardOpenOption.READ)) {
ByteBuffer bb = StreamUtils.getByteBuffer((int)ch.size());
if (ch.read(bb) < ch.size()) {
throw new IOException();
}
bb.position(0);
String sig, ver;
if (bb.remaining() >= 8) {
byte[] buf = new byte[4];
bb.get(buf);
sig = new String(buf);
bb.get(buf);
ver = new String(buf);
} else {
sig = ver = "";
}
if ("TIS ".equals(sig) && "V1 ".equals(ver)) {
if (bb.limit() > 16) {
int v1 = bb.getInt(8);
int v2 = bb.getInt(12);
return new int[]{ v1, v2 };
} else {
throw new IOException("Unexpected end of file");
}
} else if (file.getFileName().toString().toUpperCase(Locale.ENGLISH).endsWith(".TIS")) {
int tileSize = 0;
if (bb.remaining() > 16) {
tileSize = bb.getInt(12);
}
if (tileSize > 0) {
int tileCount = bb.limit() / tileSize;
return new int[]{ tileCount, tileSize };
} else {
throw new Exception("Invalid TIS tile size");
}
} else {
return new int[]{ (int)ch.size() };
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
public boolean equals(Object o)
{
if (o == this) {
return true;
} else if (o instanceof ResourceEntry) {
return getResourceName().equalsIgnoreCase(((ResourceEntry)o).getResourceName());
}
return false;
}
// --------------------- Begin Interface Comparable ---------------------
@Override
public int compareTo(ResourceEntry entry)
{
if (entry == this) {
return 0;
} else {
return getResourceName().compareToIgnoreCase(entry.getResourceName());
}
}
// --------------------- End Interface Comparable ---------------------
public Path getActualPath()
{
return getActualPath((NearInfinity.getInstance() != null) &&
BrowserMenuBar.getInstance().ignoreOverrides());
}
public ImageIcon getIcon()
{
return ResourceFactory.getKeyfile().getIcon(getExtension());
}
public long getResourceSize()
{
return getResourceSize((NearInfinity.getInstance() != null) &&
BrowserMenuBar.getInstance().ignoreOverrides());
}
public ByteBuffer getResourceBuffer() throws Exception
{
return getResourceBuffer((NearInfinity.getInstance() != null) &&
BrowserMenuBar.getInstance().ignoreOverrides());
}
public InputStream getResourceDataAsStream() throws Exception
{
return getResourceDataAsStream((NearInfinity.getInstance() != null) &&
BrowserMenuBar.getInstance().ignoreOverrides());
}
public int[] getResourceInfo() throws Exception
{
return getResourceInfo((NearInfinity.getInstance() != null) &&
BrowserMenuBar.getInstance().ignoreOverrides());
}
public String getSearchString()
{
if (searchString == null) {
try {
String extension = getExtension();
if (extension.equalsIgnoreCase("CRE")) {
searchString = CreResource.getSearchString(getResourceBuffer());
} else if (extension.equalsIgnoreCase("ITM")) {
searchString = ItmResource.getSearchString(getResourceBuffer());
} else if (extension.equalsIgnoreCase("SPL")) {
searchString = SplResource.getSearchString(getResourceBuffer());
} else if (extension.equalsIgnoreCase("STO")) {
searchString = StoResource.getSearchString(getResourceBuffer());
}
} catch (Exception e) {
if ((NearInfinity.getInstance() != null) &&
!BrowserMenuBar.getInstance().ignoreReadErrors()) {
JOptionPane.showMessageDialog(NearInfinity.getInstance(), "Error reading " + toString(),
"Error", JOptionPane.ERROR_MESSAGE);
}
searchString = "Error";
e.printStackTrace();
}
}
return searchString;
}
/**
* Returns whether the current resource matches all of the search options specified in the
* SearchOptions argument.
* @param searchOptions Contains the options to check the resource against.
* @return {@code true} if all options are matching, {@code false} otherwise.
*/
public boolean matchSearchOptions(SearchOptions searchOptions)
{
if (searchOptions != null && !searchOptions.isEmpty()) {
if ("ARE".equalsIgnoreCase(searchOptions.getResourceType())) {
return AreResource.matchSearchOptions(this, searchOptions);
} else if ("CRE".equalsIgnoreCase(searchOptions.getResourceType())) {
return CreResource.matchSearchOptions(this, searchOptions);
} else if ("EFF".equalsIgnoreCase(searchOptions.getResourceType())) {
return EffResource.matchSearchOptions(this, searchOptions);
} else if ("ITM".equalsIgnoreCase(searchOptions.getResourceType())) {
return ItmResource.matchSearchOptions(this, searchOptions);
} else if ("PRO".equalsIgnoreCase(searchOptions.getResourceType())) {
return ProResource.matchSearchOptions(this, searchOptions);
} else if ("SPL".equalsIgnoreCase(searchOptions.getResourceType())) {
return SplResource.matchSearchOptions(this, searchOptions);
} else if ("STO".equalsIgnoreCase(searchOptions.getResourceType())) {
return StoResource.matchSearchOptions(this, searchOptions);
} else if ("VVC".equalsIgnoreCase(searchOptions.getResourceType())) {
return VvcResource.matchSearchOptions(this, searchOptions);
}
}
return false;
}
/**
* Indicates whether the resource is visible for Near Infinity.
*/
public boolean isVisible()
{
return !skippedExtensions.contains(getExtension().toUpperCase(Locale.ENGLISH));
}
protected abstract Path getActualPath(boolean ignoreOverride);
public abstract long getResourceSize(boolean ignoreOverride);
public abstract String getExtension();
public abstract ByteBuffer getResourceBuffer(boolean ignoreOverride) throws Exception;
public abstract InputStream getResourceDataAsStream(boolean ignoreOverride) throws Exception;
public abstract int[] getResourceInfo(boolean ignoreOverride) throws Exception;
public abstract String getResourceName();
public abstract String getTreeFolder();
public abstract boolean hasOverride();
}