package org.tibennetwork.iarcade; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.io.FilenameUtils; import org.tibennetwork.iarcade.mame.CommandLineOptions; import org.tibennetwork.iarcade.mame.InvalidMameArgumentsException; import org.tibennetwork.iarcade.mame.Machine; import org.tibennetwork.iarcade.mame.MachineDoesntExistException; import org.tibennetwork.iarcade.mame.MachineHasNoSoftwareListException; import org.tibennetwork.iarcade.mame.MachineRepository; import org.tibennetwork.iarcade.mame.MediaDevice; import org.tibennetwork.iarcade.mame.Software; import org.tibennetwork.iarcade.mame.SoftwareNotFoundInSoftwareListsException; import org.tibennetwork.iarcade.mame.SoftwareRepository; /** * Set of Mame command line arguments */ public class CommandLineArguments { /** * Object-value which contains Machine and Software objects extracted * and instanciated from the parsed command line arguments */ public static class ExtractedMachineAndSoftwares { private Machine machine = null; private List<Software> softwares = new ArrayList<>(); public boolean hasMachine () { return this.machine != null; } public Machine getMachine () { return machine; } public void setMachine (Machine m) { this.machine = m; } public List<Software> getSoftwares() { return softwares; } public boolean hasSoftwares () { return softwares != null; } } /** * IaMmame specific options */ private Options iaRcadeOptions; /** * Mame specific options */ private CommandLineOptions mameOptions; private String[] rawArgs; private CommandLine commandLine = null; public CommandLineArguments (CommandLineOptions mameOptions, String[] rawArgs) throws InvalidMameArgumentsException { this.mameOptions = mameOptions; this.iaRcadeOptions = buildIaRcadeOptions(); this.rawArgs = rawArgs; } /** * Tell whether the command line contains the given option */ public boolean contains (String optionName) { return this.commandLine.hasOption(optionName); } /** * Tell whether the command line contains a * Mame command (-listxml, -createconfig etc.) */ public boolean containsMameCommand () { for (Option cmd: this.mameOptions.getCommands().getOptions()) { if (this.commandLine.hasOption(cmd.getOpt())) { return true; } } return false; } /** * Return Mame only args */ public String[] getMameRawArgs () { List<String> mra = new ArrayList<>(); optionsLoop: for (Option o: this.commandLine.getOptions()) { // Discard ia-rcade options for (Option ia: this.iaRcadeOptions.getOptions()) { if (o.getOpt().equals(ia.getOpt())) { continue optionsLoop; } } mra.add('-' + o.getOpt()); if (o.hasArg() || o.hasArgs()) { for (String a: this.commandLine.getOptionValues(o.getOpt())) { mra.add(a); } } } // Add non option args for (String arg: this.commandLine.getArgs()) { mra.add(arg); } return mra.toArray(new String[mra.size()]); } /** * Return non command Mame options args */ public String[] getMameOptionsRawArgs () { List<String> roa = new ArrayList<>(); optionsLoop: for (Option o: this.commandLine.getOptions()) { // Discard mame commands for (Option cmd: this.mameOptions.getCommands().getOptions()) { if (o.getOpt().equals(cmd.getOpt())) { continue optionsLoop; } } // Discard media types Mame options (ex -cart mario) for (Option mt: this.mameOptions.getMediaTypes().getOptions()) { if (o.getOpt().equals(mt.getOpt())) { continue optionsLoop; } } // Discard ia-rcade options for (Option ia: this.iaRcadeOptions.getOptions()) { if (o.getOpt().equals(ia.getOpt())) { continue optionsLoop; } } roa.add('-' + o.getOpt()); if (o.hasArg() || o.hasArgs()) { for (String a: this.commandLine.getOptionValues(o.getOpt())) { roa.add(a); } } } return roa.toArray(new String[roa.size()]); } /** * Extract and instanciate Machine and Software objects from * the parsed command-line arguments. */ public ExtractedMachineAndSoftwares extractMachineAndSoftwares ( MachineRepository mr, SoftwareRepository sr) throws InvalidMameArgumentsException, IOException, InterruptedException { ExtractedMachineAndSoftwares ems = new ExtractedMachineAndSoftwares(); // Retrieve non option arguments // There must be at most 2 non arguments : // <machine> [<software> | -<media> <software|softwarepath>] String[] cmdArgs = this.commandLine.getArgs(); if (cmdArgs.length > 2) { throw new InvalidMameArgumentsException( "Too many non option args"); } Machine m = null; if (cmdArgs.length >= 1) { try { m = mr.findByName(cmdArgs[0]); ems.setMachine(m); } catch (MachineDoesntExistException e) { throw (InvalidMameArgumentsException) new InvalidMameArgumentsException(e.getMessage()) .initCause(e); } if (cmdArgs.length > 1) { if(this.isRegularSoftwareFile(cmdArgs[1])) { throw new InvalidMameArgumentsException( "The software must be a software name from software" + " list and not a regular file"); } try { ems.getSoftwares().add( sr.findByMachineAndByName(m, cmdArgs[1])); } catch (MachineHasNoSoftwareListException | SoftwareNotFoundInSoftwareListsException | MachineDoesntExistException e) { throw (InvalidMameArgumentsException) new InvalidMameArgumentsException(e.getMessage()) .initCause(e); } } else { for (MediaDevice md: m.getMediaDevices()) { if (this.commandLine.hasOption(md.getBriefname())) { String softwareName = this.commandLine .getOptionValue(md.getBriefname()); Software s; if(this.isRegularSoftwareFile(softwareName)) { s = new Software(m, md, softwareName); } else { try { s = sr.findByMachineAndAndByMediaTypeAndByName( m, md, softwareName); } catch (MachineHasNoSoftwareListException | SoftwareNotFoundInSoftwareListsException | MachineDoesntExistException e) { throw (InvalidMameArgumentsException) new InvalidMameArgumentsException( e.getMessage()) .initCause(e); } } ems.getSoftwares().add(s); } } } } return ems; } /** * Parse args in raw string and store usefull Arguments. */ public void validate () throws InvalidMameArgumentsException { // Merge ia-rcade and Mame options Options mergedOptions = new Options(); for (Option o: mameOptions.getAllOptions().getOptions()) { mergedOptions.addOption(o); } for (Option o: iaRcadeOptions.getOptions()) { mergedOptions.addOption(o); } try { CommandLineParser parser = new DefaultParser(); this.commandLine = parser.parse( mergedOptions, rawArgs); } catch (ParseException e) { throw (InvalidMameArgumentsException) new InvalidMameArgumentsException( e.getMessage()) .initCause(e); } } /** * Determine whether the given file is a regular * software file (ie is not a softwarelist name) */ private boolean isRegularSoftwareFile (String name) { return !FilenameUtils.getExtension(name).isEmpty() || new File(name).exists(); } /** * Create Options bag for ia-rcade specific options */ private Options buildIaRcadeOptions () { // Build ia-rcade specific options Options opts = new Options(); opts.addOption("noexecmame", false, ""); return opts; } }