/* * PSXperia Converter Tool - Logging * Copyright (C) 2011 Yifan Lu (http://yifan.lu/) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.yifanlu.PSXperiaTool.Interface; import com.android.sdklib.internal.build.SignedJarBuilder; import com.yifanlu.PSXperiaTool.Extractor.CrashBandicootExtractor; import com.yifanlu.PSXperiaTool.Logger; import com.yifanlu.PSXperiaTool.PSImageExtract; import com.yifanlu.PSXperiaTool.PSXperiaTool; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.InputMismatchException; import java.util.Properties; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.DataFormatException; public class CommandLine { private static class InvalidArgumentException extends Exception { private String mMessage; public InvalidArgumentException(String message) { this.mMessage = message; } public String getMessage() { return this.mMessage; } } public static void verifyTitleID(String toVerify) throws InputMismatchException { Pattern pattern = Pattern.compile("^[A-Za-z0-9_]+$"); Matcher matcher = pattern.matcher(toVerify); if (!matcher.find()) throw new InputMismatchException("Title ID can only contain alphanumberic characters and underscores."); } public static void main(String[] args) { Logger.setLevel(Logger.DEBUG); if (args.length < 1) printHelp(); String toDo = args[0]; try { if (toDo.equals("extract") || toDo.equals("x")) doExtractData(args); if (toDo.equals("convert") || toDo.equals("c")) doConvertImage(args); if (toDo.equals("decompress") || toDo.equals("d")) doDecompressImage(args); } catch (InputMismatchException ex) { Logger.error("Input error: %s", ex.getMessage()); ex.printStackTrace(); } catch (InvalidArgumentException ex) { Logger.error("Invalid argument: %s", ex.getMessage()); printHelp(); } catch (IOException ex) { Logger.error("IO error, Java says: %s", ex.getMessage()); ex.printStackTrace(); } catch (InterruptedException ex) { Logger.error("Process exec Error, Java says: %s", ex.getMessage()); ex.printStackTrace(); } catch (DataFormatException ex) { Logger.error("Data format error, Java says: %s", ex.getMessage()); ex.printStackTrace(); } catch (GeneralSecurityException ex) { Logger.error("Error signing JAR, Java says: %s", ex.getMessage()); ex.printStackTrace(); } catch (SignedJarBuilder.IZipEntryFilter.ZipAbortException ex) { Logger.error("Error signing JAR, Java says: %s", ex.getMessage()); ex.printStackTrace(); } catch (UnsupportedOperationException ex) { Logger.error("Unsupported exception: %s", ex.getMessage()); ex.printStackTrace(); } catch (Exception ex) { Logger.error("Exception: %s", ex.getMessage()); ex.printStackTrace(); } } public static void doExtractData(String[] args) throws InvalidArgumentException, IOException, URISyntaxException { if (args.length < 4) throw new InvalidArgumentException("Not enough input."); Stack<String> stack = new Stack<String>(); stack.addAll(Arrays.asList(args)); File outputDir = new File(stack.pop()); File inputZpak = new File(stack.pop()); File inputApk = new File(stack.pop()); while (!stack.empty()) { String argument = stack.pop(); if (argument.startsWith("-")) { if (argument.equals("-v") || argument.equalsIgnoreCase("--verbose")) { Logger.setLevel(Logger.ALL); continue; } Logger.warning("Unknown option %s", argument); } } (new CrashBandicootExtractor(inputApk, inputZpak, outputDir)).extractApk(); System.exit(0); } public static void doConvertImage(String[] args) throws InvalidArgumentException, IOException, InterruptedException, GeneralSecurityException, SignedJarBuilder.IZipEntryFilter.ZipAbortException { if (args.length < 3) throw new InvalidArgumentException("Not enough input."); Stack<String> stack = new Stack<String>(); stack.addAll(Arrays.asList(args)); File outputDir = new File(stack.pop()); File inputFile = new File(stack.pop()); String titleId = stack.pop(); Properties settings = new Properties(); settings.loadFromXML(PSXperiaTool.class.getResourceAsStream("/resources/defaults.xml")); settings.put("KEY_TITLE_ID", titleId); File currentDir = new File("."); File dataDir = new File(currentDir, "/data"); Stack<String> stringList = new Stack<String>(); while (!stack.empty()) { String argument = stack.pop(); if (argument.startsWith("-")) { if (argument.equals("-v") || argument.equalsIgnoreCase("--verbose")) { Logger.setLevel(Logger.ALL); continue; } else if (argument.equals("-D")) { dataDir = new File(stringList.pop()); stringList.empty(); } else if (argument.equals("--load-xml")) { File xml = new File(stringList.pop()); settings.loadFromXML(new FileInputStream(xml)); stringList.empty(); } else if (argument.equals("--game-name")) { String name = stackToString(stringList); settings.put("KEY_DISPLAY_NAME", name); settings.put("KEY_TITLE", name); } else if (argument.equals("--description")) { settings.put("KEY_DESCRIPTION", stackToString(stringList)); } else if (argument.equals("--publisher")) { settings.put("KEY_PUBLISHER", stackToString(stringList)); } else if (argument.equals("--developer")) { settings.put("KEY_DEVELOPER", stackToString(stringList)); } else if (argument.equals("--icon-file")) { settings.put("IconFile", new File(stringList.pop())); stringList.empty(); } else if (argument.equals("--store-type")) { settings.put("KEY_STORE_TYPE", stackToString(stringList)); } else if (argument.equals("--analog-mode")) { String str = stringList.pop(); if (str.equals("true")) settings.put("KEY_ANALOG_MODE", "YES"); stringList.empty(); } else { stringList.push(argument); } } else { stringList.push(argument); } } verifyTitleID(titleId); PSXperiaTool tool = new PSXperiaTool(settings, inputFile, dataDir, outputDir); tool.startBuild(); System.exit(0); } private static String stackToString(Stack<String> stack) { String str = ""; while (!stack.isEmpty()) { str += stack.pop() + " "; } str = str.replaceAll("^\"", ""); str = str.replaceAll("\"$", ""); return str; } public static void doDecompressImage(String[] args) throws InvalidArgumentException, IOException, DataFormatException { if (args.length < 3) throw new InvalidArgumentException("Not enough input."); Stack<String> stack = new Stack<String>(); stack.addAll(Arrays.asList(args)); File outputFile = new File(stack.pop()); File inputFile = new File(stack.pop()); while (!stack.empty()) { String argument = stack.pop(); if (argument.startsWith("-")) { if (argument.equals("-v") || argument.equalsIgnoreCase("--verbose")) { Logger.setLevel(Logger.ALL); continue; } Logger.warning("Unknown option %s", argument); } } FileInputStream in = new FileInputStream(inputFile); FileOutputStream out = new FileOutputStream(outputFile); PSImageExtract extract = new PSImageExtract(in); extract.uncompress(out); out.close(); in.close(); System.exit(0); } public static void printHelp() { System.out.println("PSXPeria Converter Tool"); System.out.println(""); System.out.println("Usage:"); System.out.println(" Extract and patch data files"); System.out.println(" psxperia e[x]tract [-v|--verbose] input.apk input-data.zpak output"); System.out.println(" [-v|--verbose] Verbose output"); System.out.println(" input.apk Either com.sony.playstation.ncua94900_1.apk or com.sony.playstation.ncea00344_1.apk"); System.out.println(" input-data.zpak Either NCUA94900_1_1.zpak or NCEA00344_1_1.zpak (must match region of APK)"); System.out.println(" output Directory to extract the files"); System.out.println(""); System.out.println(" Convert PSX Image to Xperia Play APK and ZPAK"); System.out.println(" psxperia [c]onvert [OPTIONS] titleId image.iso output"); System.out.println(" titleId An unique ID, usually from the game in the format NCXAXXXXX_1"); System.out.println(" image.iso Input PSX image. Does not have to be an ISO, and valid PSX image will do. You must rip it on your own!"); System.out.println(" output Directory to output files"); System.out.println(" Options (unset options will be set to defaults):"); System.out.println(" -v|--verbose Verbose output, including image creation progress"); System.out.println(" -D directory Custom location for extracted data files, default is \"./data\""); System.out.println(" --load-xml Load options from Java properties XML"); System.out.println(" --game-name Name of the game"); System.out.println(" --description Description of the game"); System.out.println(" --publisher Publisher of the game"); System.out.println(" --developer Developer of the game"); System.out.println(" --icon-file Path to image for icon"); System.out.println(" --store-type Where to find this title (any string will do)"); System.out.println(" --analog-mode true|false, Turn on/off analog controls (game must support it)."); System.out.println(""); System.out.println(" Convert image.ps to PSX Image"); System.out.println(" psxperia [d]ecompress [-v|--verbose] input.ps output.iso"); System.out.println(" [-v|--verbose] Verbose output"); System.out.println(" input.ps image.ps from ZPAK"); System.out.println(" output.iso PSX Image to generate"); System.exit(0); } }