parent
98a235e0f4
commit
80760bc534
|
@ -161,24 +161,37 @@ public class AudioExtractor {
|
|||
if(args.length == 0) { // no arguments provided
|
||||
|
||||
switch(operation) {
|
||||
case "identify":
|
||||
|
||||
case "identify": {
|
||||
File unknownFile = retrieveFile(reader, "Please enter the path of a file: " + ANSI_BEIGE);
|
||||
identify(unknownFile);
|
||||
break;
|
||||
case "extract": // extract
|
||||
// Determine package directory
|
||||
File currentDir = new File(new File(AudioExtractor.class.getProtectionDomain().getCodeSource().getLocation().toURI())
|
||||
.getParent());
|
||||
boolean packDirFound = false;
|
||||
do {
|
||||
System.out.println(Ansi.colorize("\nPackage Directory:", Attribute.BOLD(), Attribute.CYAN_TEXT()));
|
||||
System.out.println("- " + Ansi.colorize("Current", Attribute.BRIGHT_RED_TEXT()) + " directory:\t"
|
||||
+ Ansi.colorize(currentDir.getPath(), Attribute.BRIGHT_CYAN_TEXT()));
|
||||
}
|
||||
|
||||
} while(!packDirFound);
|
||||
case "extract": {
|
||||
File packageFile = retrievePackage(reader);
|
||||
if(packageFile.isFile())
|
||||
extract(packageFile);
|
||||
else { // packageFile is a folder
|
||||
File[] packages = packageFile.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(".bin");
|
||||
}
|
||||
});
|
||||
for(File pack : packages) {
|
||||
extract(pack);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "package": // pack
|
||||
}
|
||||
|
||||
case "convert": {
|
||||
|
||||
}
|
||||
|
||||
case "package": {// pack
|
||||
break;
|
||||
}
|
||||
case "patch": // patch
|
||||
File waveFile = retrieveWave(reader);
|
||||
patch(waveFile);
|
||||
|
@ -196,6 +209,9 @@ public class AudioExtractor {
|
|||
|
||||
}
|
||||
|
||||
System.out.println("Press Enter to continue...");
|
||||
try { reader.readLine(); } catch (Exception e) {}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -280,6 +296,280 @@ public class AudioExtractor {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts audio tracks from the given package file.
|
||||
*
|
||||
* @param packageFile
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private static void extract(File packageFile) {
|
||||
|
||||
System.out.println("Name:\t" + packageFile.getName());
|
||||
System.out.println("Size:\t" + packageFile.length() + " (" + convertBytes(packageFile.length()) + ")\n");
|
||||
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile(packageFile, "r");
|
||||
LinkedHashMap<Integer, Integer> tracklist = findAudioTracks(file);
|
||||
|
||||
File dir = new File(packageFile.getAbsoluteFile().getParentFile().toPath() + "/" + FilenameUtils.removeExtension(packageFile.getName()));
|
||||
if(!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
System.out.println("Extracting " + tracklist.size() + " tracks...");
|
||||
|
||||
int digits = (int) Math.ceil(Math.log10(tracklist.size() + 1));
|
||||
int extracted = 0;
|
||||
Set<Integer> keys = tracklist.keySet();
|
||||
for(Integer address : keys) {
|
||||
int length = tracklist.get(address);
|
||||
|
||||
if(CMD_MODE)
|
||||
printProgressBar(extracted, keys.size());
|
||||
|
||||
String extension;
|
||||
byte[] bytes = new byte[2];
|
||||
file.seek(address + 0x14);
|
||||
file.read(bytes);
|
||||
int encoding = littleEndianToInt(bytes);
|
||||
switch(encoding) {
|
||||
case 0x0165: extension = "xma"; break;
|
||||
case 0x0001: extension = "wav"; break;
|
||||
default: extension = "bin"; break;
|
||||
}
|
||||
|
||||
File trackFile = new File(dir.toPath() + "/track" + String.format("%0" + digits + "d", extracted + 1) + "." + extension);
|
||||
|
||||
try (
|
||||
FileInputStream in = new FileInputStream(packageFile);
|
||||
FileOutputStream out = new FileOutputStream(trackFile);
|
||||
) {
|
||||
in.skipNBytes(address.intValue());
|
||||
bytes = new byte[length];
|
||||
int readBytes = in.read(bytes);
|
||||
out.write(bytes, 0, readBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
extracted++;
|
||||
}
|
||||
|
||||
if(CMD_MODE)
|
||||
printProgressBar(extracted, keys.size());
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("Finished.\n");
|
||||
|
||||
}
|
||||
|
||||
public static void printProgressBar(int current, int total) {
|
||||
int done = 50 * current / total;
|
||||
int todo = 50 - done;
|
||||
String doneStr = ""; // String.format("%" + done + "s", '█');
|
||||
for(int i = 0; i < done; i++)
|
||||
doneStr += '█';
|
||||
String todoStr = ""; // String.format("%" + todo + "s", '_');
|
||||
for(int i = 0; i < todo; i++)
|
||||
doneStr += '_';
|
||||
System.out.println(ANSI_BACKLINE + "Progress: |" + doneStr + todoStr + "| (" + current + "/" + total + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts audio files to the extract directory from package files located at the package directory.
|
||||
* Also supports FLAC conversion for BGM files.
|
||||
*
|
||||
* @param packDirectory
|
||||
* @param extractDirectory
|
||||
* @param compressBGM
|
||||
*/
|
||||
public static void extract(File packDirectory, File extractDirectory, boolean compressBGM) {
|
||||
|
||||
// TODO Delete
|
||||
System.out.println("packDirectory:\t" + packDirectory);
|
||||
System.out.println("extractDirectory:\t" + extractDirectory);
|
||||
|
||||
// Identify target binary files
|
||||
File[] packages = new File(packDirectory.toString()).listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(".bin");
|
||||
}
|
||||
});
|
||||
|
||||
// Identify and extract audio within binary files
|
||||
for(int i = 0; i < packages.length; i++) {
|
||||
|
||||
RandomAccessFile source;
|
||||
LinkedHashMap<Integer, Integer> tracklist = null;
|
||||
try {
|
||||
source = new RandomAccessFile(packages[i], "r");
|
||||
tracklist = findAudioTracks(source);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Binary file:\t" + packages[i] + "\n was not found. File skipped.");
|
||||
continue;
|
||||
} catch (IOException e) {
|
||||
System.out.println("Binary file:\t" + packages[i] + "\n could not be read. File skipped.");
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("packages[" + i + "]:\t" + packages[i]);
|
||||
|
||||
File dir = new File(extractDirectory.getPath() + "/" + FilenameUtils.removeExtension(packages[i].getName()));
|
||||
if(!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
// Extract and write WAV files in directory
|
||||
Set<Integer> keys = tracklist.keySet();
|
||||
int track = 1;
|
||||
|
||||
for(Integer key : keys) {
|
||||
|
||||
String name = String.format("track%04d", track);
|
||||
{ // Extract WAV files
|
||||
File wav = null;
|
||||
try {
|
||||
|
||||
// create file for storing WAV data
|
||||
wav = new File(dir.getPath() + "/" + name + ".wav");
|
||||
if(!wav.exists())
|
||||
wav.createNewFile();
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("Saving track " + String.format("%d (@0x%08X)", track, key) + " to " + wav + String.format(" (%d bytes)", tracklist.get(key)));
|
||||
|
||||
// write selection to file
|
||||
try (
|
||||
FileInputStream inStream = new FileInputStream(packages[i]);
|
||||
FileOutputStream outStream = new FileOutputStream(wav)
|
||||
) {
|
||||
inStream.skipNBytes(key.intValue());
|
||||
byte[] trackBytes = new byte[tracklist.get(key)];
|
||||
int readBytes = inStream.read(trackBytes);
|
||||
outStream.write(trackBytes, 0, readBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("An error occurred when attempting to write " + name + " to file:\t" + wav);
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
track++;
|
||||
|
||||
}
|
||||
|
||||
if(compressBGM && packages[i].getName().equals("pack_bgm.bin")) {
|
||||
|
||||
// find WAV files
|
||||
File[] WAV_Files = dir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(".wav");
|
||||
}
|
||||
});
|
||||
|
||||
// convert WAV files to FLAC
|
||||
FLAC_FileEncoder ffe = new FLAC_FileEncoder();
|
||||
|
||||
for(File wav : WAV_Files) {
|
||||
|
||||
try {
|
||||
File flac = new File(dir.getPath() + "/" + FilenameUtils.removeExtension(wav.getName()) + ".flac");
|
||||
if(!flac.exists())
|
||||
flac.createNewFile();
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("Compressing WAV to FLAC:\t" + flac);
|
||||
|
||||
ffe.encode(wav, flac);
|
||||
} catch (IOException e) {
|
||||
System.out.println("An error occurred when attempting to write file.");
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
System.out.print("Deleting WAV files");
|
||||
// delete WAV files
|
||||
for(File wav : WAV_Files) {
|
||||
boolean deleted = false;
|
||||
while(!deleted) {
|
||||
try {
|
||||
Files.delete(wav.toPath());
|
||||
deleted = true;
|
||||
} catch(Exception e) {
|
||||
System.out.print('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to prompt user to select a package file, or folder containing one or more packages.
|
||||
*
|
||||
* @param reader
|
||||
* @return file
|
||||
*/
|
||||
private static File retrievePackage(BufferedReader reader) {
|
||||
|
||||
String prompt = "Please enter the path of a package: " + ANSI_BEIGE;
|
||||
|
||||
File packageFile = null;
|
||||
boolean valid = false;
|
||||
do {
|
||||
|
||||
// Retrieve an audio file
|
||||
packageFile = retrieveFileOrFolder(reader, prompt);
|
||||
|
||||
if(packageFile.isFile()) {
|
||||
// File must have .bin extension
|
||||
String name = packageFile.getName();
|
||||
int extIndex = name.lastIndexOf('.');
|
||||
String extension = null;
|
||||
if(extIndex > 0 && extIndex < name.length() - 1)
|
||||
extension = name.substring(extIndex + 1);
|
||||
if(extension != null && extension.equalsIgnoreCase("bin"))
|
||||
valid = true;
|
||||
} else { // packageFile is folder
|
||||
; // Folder should have a .bin file
|
||||
File[] contents = packageFile.listFiles();
|
||||
for(File file : contents) {
|
||||
String name = file.getName();
|
||||
int extIndex = name.lastIndexOf('.');
|
||||
String extension = null;
|
||||
if(extIndex > 0 && extIndex < name.length() - 1)
|
||||
extension = name.substring(extIndex + 1);
|
||||
if(extension != null && extension.equalsIgnoreCase("bin")) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!valid) {
|
||||
if(packageFile.isFile())
|
||||
System.out.println("File does not have a .BIN file extension.");
|
||||
else System.out.println("Directory does not contain a .BIN file.");
|
||||
}
|
||||
|
||||
} while(!valid);
|
||||
|
||||
return packageFile;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to prompt user to select a program task.
|
||||
|
@ -350,15 +640,15 @@ public class AudioExtractor {
|
|||
/**
|
||||
* Examines a given file and reads some of its properties.
|
||||
*
|
||||
* @param unknownFile
|
||||
* @param givenFile
|
||||
*/
|
||||
public static void identify(File unknownFile) {
|
||||
public static void identify(File givenFile) {
|
||||
|
||||
// TODO check for characteristics of BIN or WAV files
|
||||
String name = unknownFile.getName();
|
||||
String name = givenFile.getName();
|
||||
System.out.println("Name:\t" + name);
|
||||
|
||||
long size = unknownFile.length();
|
||||
long size = givenFile.length();
|
||||
System.out.println("Size:\t" + size + " Bytes" + (size > 1024 ? " (" + convertBytes(size) + ")" : "") + "\n");
|
||||
|
||||
// file extension
|
||||
|
@ -368,14 +658,13 @@ public class AudioExtractor {
|
|||
extension = name.substring(extIndex + 1);
|
||||
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile(unknownFile, "r");
|
||||
RandomAccessFile file = new RandomAccessFile(givenFile, "r");
|
||||
switch(extension.toLowerCase()) {
|
||||
case "bin": {
|
||||
|
||||
break;
|
||||
}
|
||||
case "flac": {
|
||||
|
||||
LinkedHashMap<Integer, Integer> tracklist = findAudioTracks(file);
|
||||
System.out.println(tracklist.size() + " Tracks (" + convertBytes(size / tracklist.size()) + " avg size)\n");
|
||||
System.out.println("Format Info");
|
||||
readFormatChunk(file, 0x0C);
|
||||
break;
|
||||
}
|
||||
case "wav":
|
||||
|
@ -402,15 +691,15 @@ public class AudioExtractor {
|
|||
break;
|
||||
}
|
||||
case ASCII_ALIG: {
|
||||
readAlignmentChunk(file, (int) i);
|
||||
i = readAlignmentChunk(file, (int) i) - 4;
|
||||
break;
|
||||
}
|
||||
case ASCII_seek: {
|
||||
readx2stChunk(file, (int) i);
|
||||
i = readx2stChunk(file, (int) i) - 4;
|
||||
break;
|
||||
}
|
||||
case ASCII_x2st: {
|
||||
readx2stChunk(file, (int) i);
|
||||
i = readx2stChunk(file, (int) i) - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -572,8 +861,7 @@ public class AudioExtractor {
|
|||
System.out.println(formatAddress(offset + 0x04, file.length()) + ":\t" + size + " Bytes" + (size > 1024 ? " (" + convertBytes(size) + ")" : ""));
|
||||
}
|
||||
|
||||
// 0x08 4B manufacturer code
|
||||
// parseField(file, offset + 0x08, 4, " manufacturer code");
|
||||
// 0x08 4 bytes manufacturer code
|
||||
byte[] bytes = new byte[4];
|
||||
file.seek(offset + 0x08);
|
||||
file.read(bytes);
|
||||
|
@ -582,9 +870,7 @@ public class AudioExtractor {
|
|||
if(relevantBytes == 3)
|
||||
code = String.format("%02XH %02XH %02XH", bytes[1], bytes[2], bytes[3]);
|
||||
else code = String.format("%02XH", bytes[3]);
|
||||
|
||||
System.out.print(formatAddress(offset + 0x08, file.length()) + ":\t");
|
||||
|
||||
boolean found = false;
|
||||
InputStream filestream = AudioExtractor.class.getResourceAsStream("/manufacturer.csv");
|
||||
InputStreamReader streamReader = new InputStreamReader(filestream);
|
||||
|
@ -604,7 +890,6 @@ public class AudioExtractor {
|
|||
System.out.print("Unknown (" + code + ")");
|
||||
System.out.println(" manufacturer");
|
||||
|
||||
// 0x0C 4B product code
|
||||
parseField(file, offset + 0x0C, 4, " product code");
|
||||
parseField(file, offset + 0x10, 4, "-nanosecond sample period");
|
||||
parseField(file, offset + 0x14, 4, " MIDI unity note");
|
||||
|
@ -652,7 +937,14 @@ public class AudioExtractor {
|
|||
System.out.println(formatAddress(loopOffset + 0x08, file.length()) + ":\tLoop end @ sample " + loopEnd);
|
||||
|
||||
parseField(file, loopOffset + 0x10, 4, " loop fraction");
|
||||
parseField(file, loopOffset + 0x14, 4, " repeat count");
|
||||
|
||||
file.seek(loopOffset + 0x14);
|
||||
file.read(bytes);
|
||||
int repeat = littleEndianToInt(bytes);
|
||||
if(repeat == 0)
|
||||
System.out.println(formatAddress(loopOffset + 0x14, file.length()) + ":\tRepeat indefinitely");
|
||||
else System.out.println(formatAddress(loopOffset + 0x14, file.length()) + ":\t" + repeat + "repeat count");
|
||||
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
|
@ -753,145 +1045,6 @@ public class AudioExtractor {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts audio files to the extract directory from package files located at the package directory.
|
||||
* Also supports FLAC conversion for BGM files.
|
||||
*
|
||||
* @param packDirectory
|
||||
* @param extractDirectory
|
||||
* @param compressBGM
|
||||
*/
|
||||
public static void extract(File packDirectory, File extractDirectory, boolean compressBGM) {
|
||||
|
||||
// TODO Delete
|
||||
System.out.println("packDirectory:\t" + packDirectory);
|
||||
System.out.println("extractDirectory:\t" + extractDirectory);
|
||||
|
||||
// Identify target binary files
|
||||
File[] packages = new File(packDirectory.toString()).listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(".bin");
|
||||
}
|
||||
});
|
||||
|
||||
// Identify and extract audio within binary files
|
||||
for(int i = 0; i < packages.length; i++) {
|
||||
|
||||
RandomAccessFile source;
|
||||
LinkedHashMap<Integer, Integer> tracklist = null;
|
||||
try {
|
||||
source = new RandomAccessFile(packages[i], "r");
|
||||
tracklist = findAudioTracks(source);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Binary file:\t" + packages[i] + "\n was not found. File skipped.");
|
||||
continue;
|
||||
} catch (IOException e) {
|
||||
System.out.println("Binary file:\t" + packages[i] + "\n could not be read. File skipped.");
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("packages[" + i + "]:\t" + packages[i]);
|
||||
|
||||
File dir = new File(extractDirectory.getPath() + "/" + FilenameUtils.removeExtension(packages[i].getName()));
|
||||
if(!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
// Extract and write WAV files in directory
|
||||
Set<Integer> keys = tracklist.keySet();
|
||||
int track = 1;
|
||||
|
||||
for(Integer key : keys) {
|
||||
|
||||
String name = String.format("track%04d", track);
|
||||
{ // Extract WAV files
|
||||
File wav = null;
|
||||
try {
|
||||
|
||||
// create file for storing WAV data
|
||||
wav = new File(dir.getPath() + "/" + name + ".wav");
|
||||
if(!wav.exists())
|
||||
wav.createNewFile();
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("Saving track " + String.format("%d (@0x%08X)", track, key) + " to " + wav + String.format(" (%d bytes)", tracklist.get(key)));
|
||||
|
||||
// write selection to file
|
||||
try (
|
||||
FileInputStream inStream = new FileInputStream(packages[i]);
|
||||
FileOutputStream outStream = new FileOutputStream(wav)
|
||||
) {
|
||||
inStream.skipNBytes(key.intValue());
|
||||
byte[] trackBytes = new byte[tracklist.get(key)];
|
||||
int readBytes = inStream.read(trackBytes);
|
||||
outStream.write(trackBytes, 0, readBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("An error occurred when attempting to write " + name + " to file:\t" + wav);
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
track++;
|
||||
|
||||
}
|
||||
|
||||
if(compressBGM && packages[i].getName().equals("pack_bgm.bin")) {
|
||||
|
||||
// find WAV files
|
||||
File[] WAV_Files = dir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(".wav");
|
||||
}
|
||||
});
|
||||
|
||||
// convert WAV files to FLAC
|
||||
FLAC_FileEncoder ffe = new FLAC_FileEncoder();
|
||||
|
||||
for(File wav : WAV_Files) {
|
||||
|
||||
try {
|
||||
File flac = new File(dir.getPath() + "/" + FilenameUtils.removeExtension(wav.getName()) + ".flac");
|
||||
if(!flac.exists())
|
||||
flac.createNewFile();
|
||||
|
||||
//TODO Delete
|
||||
System.out.println("Compressing WAV to FLAC:\t" + flac);
|
||||
|
||||
ffe.encode(wav, flac);
|
||||
} catch (IOException e) {
|
||||
System.out.println("An error occurred when attempting to write file.");
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
System.out.print("Deleting WAV files");
|
||||
// delete WAV files
|
||||
for(File wav : WAV_Files) {
|
||||
boolean deleted = false;
|
||||
while(!deleted) {
|
||||
try {
|
||||
Files.delete(wav.toPath());
|
||||
deleted = true;
|
||||
} catch(Exception e) {
|
||||
System.out.print('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Packs WAV files located at the extract directory into BIN files at the package directory.
|
||||
|
@ -1076,6 +1229,39 @@ public class AudioExtractor {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to prompt user to select a file or folder.
|
||||
*
|
||||
* @param reader
|
||||
* @return file or folder
|
||||
*/
|
||||
private static File retrieveFileOrFolder(BufferedReader reader, String prompt) {
|
||||
|
||||
File file = null;
|
||||
|
||||
String input = null;
|
||||
boolean valid = false;
|
||||
do {
|
||||
System.out.print(prompt);
|
||||
try {
|
||||
input = reader.readLine();
|
||||
if(input == null)
|
||||
throw new IOException("Invalid file.");
|
||||
file = new File(input);
|
||||
if(file.exists()) {
|
||||
valid = true;
|
||||
} else System.out.println(Ansi.colorize("File does not exist."));
|
||||
} catch (IOException e) {
|
||||
System.out.println(Ansi.colorize("Invalid file."));
|
||||
}
|
||||
} while(!valid);
|
||||
|
||||
System.out.print(Ansi.colorize("\n"));
|
||||
|
||||
return file;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to prompt user to select a file.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue