// 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"; }