package tools;
//<editor-fold defaultstate="collapsed" desc="Import statements">
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import gui.Dialog;
//</editor-fold>
/**
* This class is used to simplify file input/output operations.
* @author Jiangcheng Oliver Chu
*/
public class FileIO {
public static String addFileExtensionIfNeeded(String filePath,
String extension) {
//The user has already specified a file extension. Do not add a new
//one.
if (filePath.contains("."))
return filePath;
if (!extension.startsWith("."))
extension = "." + extension;
return filePath + extension;
}
public static String removeFileExtension(String fileNameWithExtension) {
int maxLength = fileNameWithExtension.length();
for (int i = maxLength - 1; i >= 0; i--) {
if (fileNameWithExtension.charAt(i) == '.')
return StrTools.slice(fileNameWithExtension,0,i);
}
//We could not find the file extension, so return the fileName as is.
return fileNameWithExtension;
}
static int getFileSize(String fileName) {
File fileObj = new File(fileName);
if (!fileObj.canRead())
return 0;
long fileSize = fileObj.length();
if (fileSize >= 2147483648L)
return Integer.MAX_VALUE;
else
return (int)fileSize;
}
/**
* Checks if a file (or folder) exists or not.
* @return true if file exists, false otherwise.
*/
public static boolean exists(String fileName)
{
File fileObj = new File(fileName);
return fileObj.exists();
}
/**
* Checks if a file can be read and written.
* @return true if file can be read and written, false otherwise.
*/
public static boolean canReadAndWrite(String fileName)
{
File fileObj = new File(fileName);
return (fileObj.canRead() && fileObj.canWrite());
}
/**
* Takes the contents of a file and returns a string with those contents.
* <br /><br />Do NOT make this method private. It needs to be used by some
* classes that work with the binary tables.
* @param fileName
* @return Contents of file (as string)
*/
public static String fileToStr(String fileName)
{
String outString="";
try
{
InputStream fileObj = new FileInputStream(fileName);
int maxReadSize = fileObj.available();
for (int i=0;i < maxReadSize;i++)
outString += (char)fileObj.read();
fileObj.close();
}
catch(IOException exceptionInfo)
{
Dialog.errorBox("File reading error\n"+exceptionInfo,true);
}
return outString;
}
/**
* Stores the string fileContents into file with path fileName.
* @param fileContents
* @param fileName
*/
private static void strToFile(String fileContents,String fileName)
{
int maxLen = fileContents.length();
try
{
OutputStream fileObj = new FileOutputStream(fileName);
for (int index=0;index < maxLen;index++)
fileObj.write(fileContents.charAt(index));
fileObj.close();
}
catch(IOException exceptionInfo)
{
Dialog.errorBox("File writing error\n"+exceptionInfo,true);
}
}
/**
* Converts file contents into a string, but the file must be a text-file
* with line breaks. System newlines (\r\n) get converted to \n.
* @param fileName
* @return
*/
public static String textFileToStr(String fileName)
{
return StrTools.unixifyNewlines(fileToStr(fileName));
}
public static void strToTextFile(String fileContents,String fileName)
{
strToFile(StrTools.convertNewlines(fileContents),fileName);
}
/**
* Appends the string 'append' to the specified file.
* @param append
* @param fileName
*/
private static void appendStrToFile(String append,String fileName)
{
try
{
BufferedWriter fileObj =
new BufferedWriter(new FileWriter(fileName, true));
fileObj.write(append);
fileObj.close();
}
catch (IOException exceptionInfo)
{
Dialog.errorBox("File appending error: "+exceptionInfo, true);
}
}
/**
* Appends the string 'append' to the specified file. The 'append' has
* all unix-style newlines (\n) converted to native newlines first.
* @param append
* @param fileName
*/
public static void appendTextStrToFile(String append, String fileName)
{
appendStrToFile(StrTools.convertNewlines(append),fileName);
}
/**
* Converts a full file path to a relative file path.
* If you give this a path such as<br />
* C:\Users\Javagrams\MYPROGRAM.jar\yes\hello.txt<br />
* It will return "yes/hello.txt"<br />
* And yes, if you're on Windows, the backslashes will be converted to
* forward slashes.<br />
* Does NOT support "up one level" folders. For example, ../../image.bmp
* will never be returned.
* @param filePath
* @return Relative path
*/
public static String fullPathToRelPath(String filePath)
{
String currentWorkingDir = System.getProperty("user.dir");
currentWorkingDir = currentWorkingDir.replace('\\', '/');
filePath = filePath.replace('\\','/');
if (!filePath.startsWith(currentWorkingDir))
{
Dialog.errorBox("Can't get a relative path using:\n"+
"Filepath = "+filePath+
"\nProgrampath = "+currentWorkingDir,true);
}
//Remove the current working dir prefix from the file path.
String relativePath = StrTools.slice(filePath,currentWorkingDir.length());
if (relativePath.startsWith("/"))
relativePath = StrTools.slice(relativePath,1);
return relativePath;
}
/**
* Converts a full path such as "C:/Users/Documents/hello.txt" to a
* simple filename such as "hello.txt".
* @param filePath
* @return Simple Filename
*/
public static String fullPathToFileName(String filePath) {
int maxLength = filePath.length();
String fileNameBuffer = "";
for (int x = maxLength-1; x >= 0; x--) {
char currentChar = filePath.charAt(x);
if (currentChar == '/' || currentChar == '\\')
return fileNameBuffer;
fileNameBuffer = currentChar + fileNameBuffer;
}
return fileNameBuffer;
}
/**
* Creates a single folder.
* If the folder already exists, this does not recreate it.
*/
public static void makeFolder(String folderName) {
File folderObj = new File(folderName);
if (folderObj.exists())
return;
boolean isCreated = folderObj.mkdir();
if (!isCreated)
Dialog.errorBox("Could not create folder: "+folderName,true);
return;
}
/**
* Deletes the file or directory determined by path.
* @param path
*/
public static void delete(String path)
{
/* Thanks a lot to
* <http://www.java2s.com/Code/
* Java/File-Input-Output/DeletefileusingJavaIOAPI.htm>
* for their useful information.
*/
File deleteFileObj = new File(path);
if (!deleteFileObj.exists())
Dialog.errorBox("Cannot delete file "+path+" because that file\n"+
"doesn't exist!", true);
if (!deleteFileObj.canWrite())
Dialog.errorBox("Cannot delete file "+path+" because that file\n"+
"is write-protected.", true);
if (deleteFileObj.isDirectory())
{//Check to make sure the folder has no files in it.
int filesInDirectory = deleteFileObj.list().length;
if (filesInDirectory > 0)
Dialog.errorBox("Cannot delete folder "+path+" because there\n"+
"are still files in the folder.",true);
}
boolean deleteStatus = deleteFileObj.delete();
if (!deleteStatus)
//Our delete failed, even after all that checking!
Dialog.errorBox("Cannot delete file "+path+" for unknown reason.",
true);
}
public static boolean deleteWithoutErrors(String path)
{
File deleteFileObj = new File(path);
if (!deleteFileObj.exists() || !deleteFileObj.canWrite())
return false;
if (deleteFileObj.isDirectory())
{//Check to make sure the folder has no files in it.
int filesInDirectory = deleteFileObj.list().length;
if (filesInDirectory > 0)
return false;
}
return deleteFileObj.delete();
}
/**
* Copies a file from fileName1 to fileName2.
* @param fileName1
* @param fileName2
*/
public static void copyFile(String fileName1,String fileName2) {
try {
File fileObj1 = new File(fileName1);
File fileObj2 = new File(fileName2);
InputStream inputObj = new FileInputStream(fileObj1);
OutputStream outputObj = new FileOutputStream(fileObj2);
byte[] byteBuffer = new byte[1024];
int currentLength;
while ((currentLength = inputObj.read(byteBuffer)) > 0) {
outputObj.write(byteBuffer,0,currentLength);
}
inputObj.close();
outputObj.close();
} catch (FileNotFoundException exceptionInfo) {
showCopyError(fileName1,fileName2);
} catch (IOException exceptionInfo) {
showCopyError(fileName1,fileName2);
}
}
private static void showCopyError(String fileName1,String fileName2) {
Dialog.errorBox("Could not copy file "+fileName1+" to "+
fileName2, true);
}
public static String readHex(String fileName,int begin,int end) {
byte[] bytesRead = {};
try {
File fileObj = new File(fileName);
RandomAccessFile RAFObj = new RandomAccessFile(fileObj,"r");
if (end > fileObj.length())
//Yeah, it's a long to int conversion. But an int cannot be
//bigger than a long unless the long fits into an int, so this
//is fine.
end = (int)fileObj.length();
if (begin < 0)
begin = 0;
if (begin > end)
begin = end;
bytesRead = new byte[end - begin];
RAFObj.seek(begin);
RAFObj.read(bytesRead);
RAFObj.close();
} catch (IOException exceptionInfo) {
Dialog.errorBox("There was an error while attempting to read the\n"+
"file: "+fileName,true);
}
return NumberTools.bytesToHex(bytesRead);
}
public static void writeHex(String fileName,String hexString,int begin,
boolean isGameExec) {
try {
File fileObj = new File(fileName);
RandomAccessFile RAFObj = new RandomAccessFile(fileObj,"rw");
if (begin > fileObj.length())
return;
if (begin < 0)
begin = 0;
byte[] bytesToWrite = NumberTools.hexToBytes(hexString);
RAFObj.seek(begin);
//It is okay to write past the end of the file. The .write()
//method will simply append the extra bytes.
RAFObj.write(bytesToWrite);
RAFObj.close();
} catch (IOException exceptionInfo) {
if (isGameExec) {
Dialog.errorBox("There was an error while attempting to write"+
"\ndata to the game exe: "+fileName+"\n\n"+
"Make sure the exe is not read-only.\n"+
"Also, close OllyDbg if it's open.",true);
} else {
Dialog.errorBox("There was an error while attempting to write"+
"\ndata to the file: "+fileName+"\n\n"+
"Make sure the file is not read-only.\n"+
"Also, close other programs that might be\n"+
"editing the file.",true);
}
}
}
static void saveErrorToLogFile(String errorMessage) {
File checkFileObj = new File("error.log");
boolean fileExists = checkFileObj.exists();
if (fileExists && (!checkFileObj.canRead() ||
!checkFileObj.canWrite())) {
//Since an error already occurred, we can't show more errors.
//Just return without a trace.
return;
}
//<editor-fold defaultstate="collapsed" desc="File to str without errors">
String outString = "";
if (fileExists) {
try {
InputStream errorFileObj = new FileInputStream("error.log");
int maxReadSize = errorFileObj.available();
for (int i=0;i < maxReadSize;i++)
outString += (char)errorFileObj.read();
errorFileObj.close();
} catch(IOException exceptionInfo) {
return;
}
outString = StrTools.unixifyNewlines(outString);
outString = errorMessage + "\n\n====================\n" +
outString;
} else {
outString = errorMessage;
}
//</editor-fold>
outString = StrTools.convertNewlines(outString);
//<editor-fold defaultstate="collapsed" desc="Str to File without errors">
int maxLen = outString.length();
try {
OutputStream fileObj = new FileOutputStream("error.log");
for (int index=0;index < maxLen;index++)
fileObj.write(outString.charAt(index));
fileObj.close();
} catch(IOException exceptionInfo) {
return;
}
//</editor-fold>
}
}//END MAIN CLASS