// Copyright 2011-2012 Paulo Augusto Peccin. See licence.txt distributed with this file.
package org.javatari.pc.cartridge;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessControlException;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.jnlp.FileContents;
import javax.swing.JOptionPane;
import org.javatari.atari.cartridge.Cartridge;
import org.javatari.atari.cartridge.CartridgeCreator;
import org.javatari.atari.cartridge.CartridgeDatabase;
import org.javatari.atari.cartridge.ROM;
import org.javatari.atari.cartridge.ROMFormatUnsupportedException;
import org.javatari.parameters.Parameters;
public final class ROMLoader {
public static Cartridge load(String url, boolean provided) {
try {
return load(new URL(url), provided);
} catch (MalformedURLException ex) {
generalErrorMessage(ex, url);
}
return null;
}
public static Cartridge load(File file) {
try {
return load(file.toURI().toURL(), false);
} catch (MalformedURLException ex) {
generalErrorMessage(ex, file.getPath());
} catch (AccessControlException ex) {
generalErrorMessage(ex, file.getPath());
}
return null;
}
public static Cartridge load(URL url, boolean provided) {
InputStream stream = null;
try {
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
stream = conn.getInputStream();
return createFromExternalURL(stream, url.toString(), provided);
} catch (AccessControlException ex) {
generalErrorMessage(ex, url.toString());
} catch (IOException ex) {
generalErrorMessage(ex, url.toString());
}
return null;
}
public static Cartridge load(FileContents fileContents) {
String fileName = "<unknown>";
try {
fileName = fileContents.getName();
InputStream stream = fileContents.getInputStream();
return createFromExternalURL(stream, fileName, false);
} catch (IOException ex) {
generalErrorMessage(ex, fileName);
return null;
}
}
public static Cartridge load(BuiltInROM builtInROM) {
if (builtInROM.label != null) Parameters.CARTRIDGE_LABEL = builtInROM.label;
if (builtInROM.labelColors != null) Parameters.setCartridgeLabelColors(builtInROM.labelColors);
return load(builtInROM.url, true);
}
private static Cartridge createFromExternalURL(InputStream stream, String romURL, boolean provided) {
System.out.println("Loading Cartridge from: " + romURL);
BufferedInputStream buffer = bufferedStream(stream);
try {
try {
// First try reading and creating directly
return createCartridge(buffer, romURL, provided);
} catch (ROMFormatUnsupportedException ex) {
// If it fails, try assuming its a compressed stream (zip)
buffer.reset();
InputStream romFromZIP = getFirstROMFromZIP(buffer);
if (romFromZIP == null) throw ex; // Probably not zipped either
return createCartridge(romFromZIP, romURL, provided);
}
} catch (ROMFormatUnsupportedException ex) {
romFormatUnsupportedErrorMessage(ex, romURL);
} catch (IOException ex) {
generalErrorMessage(ex, romURL);
} finally {
try {
stream.close();
buffer.close();
} catch (IOException e) {}
}
return null;
}
private static Cartridge createCartridge(InputStream stream, String romURL, boolean provided) throws IOException, ROMFormatUnsupportedException {
ROM rom = createROM(stream, romURL);
if (provided) CartridgeDatabase.adjustInfoOfROMProvided(rom);
return CartridgeCreator.create(rom);
}
private static ROM createROM(InputStream stream, String romURL) throws IOException {
byte[] buffer = new byte[MAX_STREAM_SIZE];
int totalRead = 0;
do {
int read = stream.read(buffer, totalRead, MAX_STREAM_SIZE - totalRead);
if (read == -1) break; // End of Stream
totalRead += read;
} while(totalRead < MAX_STREAM_SIZE);
byte[] content = (totalRead > 0) ? Arrays.copyOf(buffer, totalRead) : new byte[0];
return new ROM(romURL.trim(), content);
}
private static InputStream getFirstROMFromZIP(InputStream stream) throws IOException, ROMFormatUnsupportedException {
ZipInputStream zipStream = new ZipInputStream(stream);
while(true) {
ZipEntry entry = zipStream.getNextEntry();
if (entry == null) return null;
String entryName = entry.getName().toUpperCase();
for (int i = 0; i < VALID_LOAD_FILE_EXTENSIONS.length; i++)
if (entryName.endsWith(VALID_LOAD_FILE_EXTENSIONS[i].toUpperCase()))
return zipStream;
}
}
private static BufferedInputStream bufferedStream(InputStream stream) {
BufferedInputStream buf = new BufferedInputStream(stream, MAX_STREAM_SIZE);
buf.mark(MAX_STREAM_SIZE);
return buf;
}
private static void generalErrorMessage(Exception ex, String location) {
System.out.println("Could not load Cartridge from: " + location);
System.out.println(ex);
String tLoc = location == null ? "" : location.trim();
if (tLoc.length() > 80) tLoc = tLoc.substring(0, 79) + "...";
JOptionPane.showMessageDialog(
null,
"Could not load Cartridge from:\n" + tLoc + "\n\n" + ex.getClass().getSimpleName() + ": " + ex.getMessage(),
"Error loading Cartridge",
JOptionPane.ERROR_MESSAGE
);
}
private static void romFormatUnsupportedErrorMessage(ROMFormatUnsupportedException ex, String location) {
System.out.println("Could not load Cartridge from: " + location);
System.out.println(ex.getMessage());
String tLoc = location == null ? "" : location.trim();
if (tLoc.length() > 80) tLoc = tLoc.substring(0, 79) + "...";
JOptionPane.showMessageDialog(
null,
"Could not load Cartridge from:\n" + tLoc + "\n\n" + ex.getMessage(),
"Error loading Cartridge",
JOptionPane.ERROR_MESSAGE
);
}
private static final int MAX_ROM_SIZE = 512 * 1024;
private static final int MAX_STREAM_SIZE = MAX_ROM_SIZE + 1024;
public static final String VALID_LOAD_FILES_DESC = "ROM and Savestate files (.bin .rom .a26 .zip .jat)";
public static final String[] VALID_LOAD_FILE_EXTENSIONS = {"bin", "rom", "a26", "zip", "jat"};
public static final String VALID_STATE_FILE_DESC = "Javatari Savestate files (.jat)";
public static final String VALID_STATE_FILE_EXTENSION = "jat";
}