mirror of
https://github.com/AdAstra-LD/DS-Pokemon-Rom-Editor.git
synced 2026-05-11 06:24:14 -05:00
378 lines
12 KiB
C#
378 lines
12 KiB
C#
/*
|
|
* This file is part of NSMB Editor 5.
|
|
*
|
|
* NSMB Editor 5 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.
|
|
*
|
|
* NSMB Editor 5 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 NSMB Editor 5. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.IO;
|
|
|
|
namespace NSMBe4.DSFileSystem
|
|
{
|
|
public class File : IComparable
|
|
{
|
|
public bool isSystemFile;
|
|
byte[] file2;
|
|
protected string nameP;
|
|
public string name { get { return nameP; } }
|
|
|
|
protected int idP;
|
|
public int id { get { return idP; } }
|
|
|
|
protected Directory parentDirP;
|
|
public Directory parentDir { get { return parentDirP; } }
|
|
|
|
//if allocationFile is not null,
|
|
//these are the offsets within the alloc file where the offsets
|
|
//of this file are found.
|
|
|
|
protected File beginFile;
|
|
protected int beginOffset;
|
|
protected File endFile;
|
|
protected int endOffset;
|
|
protected bool endIsSize; //means that the end offset is the size of the file
|
|
protected bool fixedFile; //means that the file cant be moved nor changed size
|
|
|
|
public int fileBegin;
|
|
public int fileSize;
|
|
|
|
public int alignment = 4; // word align by default
|
|
public bool canChangeOffset = true; //false for arm9 and 7 bins
|
|
|
|
public Filesystem parent;
|
|
|
|
protected Object editedBy = null;
|
|
public Boolean beingEdited
|
|
{
|
|
get { return editedBy != null; }
|
|
}
|
|
|
|
public File(Filesystem parent, Directory parentDir, string name)
|
|
{
|
|
this.parent = parent;
|
|
this.parentDirP = parentDir;
|
|
this.nameP = name;
|
|
this.fileBegin = 0;
|
|
this.fileSize = (int)parent.s.Length;
|
|
this.isSystemFile = true;
|
|
}
|
|
|
|
public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, File alFile, int alBeg, int alEnd)
|
|
{
|
|
this.parent = parent;
|
|
this.parentDirP = parentDir;
|
|
this.isSystemFile = systemFile;
|
|
this.idP = id;
|
|
this.nameP = name;
|
|
this.beginFile = alFile;
|
|
this.endFile = alFile;
|
|
this.beginOffset = alBeg;
|
|
this.endOffset = alEnd;
|
|
refreshOffsets();
|
|
}
|
|
|
|
public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, File alFile, int alBeg, int alEnd, bool endsize)
|
|
{
|
|
this.parent = parent;
|
|
this.parentDirP = parentDir;
|
|
this.isSystemFile = systemFile;
|
|
this.idP = id;
|
|
this.nameP = name;
|
|
this.beginFile = alFile;
|
|
this.endFile = alFile;
|
|
this.beginOffset = alBeg;
|
|
this.endOffset = alEnd;
|
|
this.endIsSize = endsize;
|
|
refreshOffsets();
|
|
}
|
|
|
|
public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, int alBeg, int alSize)
|
|
{
|
|
this.parent = parent;
|
|
this.parentDirP = parentDir;
|
|
this.isSystemFile = systemFile;
|
|
this.idP = id;
|
|
this.nameP = name;
|
|
this.fileBegin = alBeg;
|
|
this.fileSize = alSize;
|
|
refreshOffsets();
|
|
}
|
|
|
|
public virtual byte[] getContents()
|
|
{
|
|
// enableEdition();
|
|
byte[] file = new byte[fileSize];
|
|
parent.s.Seek(fileBegin, SeekOrigin.Begin);
|
|
parent.s.Read(file, 0, file.Length);
|
|
return file;
|
|
}
|
|
|
|
public void dumpFile(int ind)
|
|
{
|
|
for (int i = 0; i < ind; i++)
|
|
Console.Out.Write(" ");
|
|
Console.Out.WriteLine("[" + id + "] " + name + ", at " + fileBegin.ToString("X") + ", size: " + fileSize);
|
|
}
|
|
|
|
|
|
public virtual void refreshOffsets()
|
|
{
|
|
if (beginFile != null)
|
|
fileBegin = (int)beginFile.getUintAt(beginOffset) + parent.fileDataOffset;
|
|
|
|
if (endFile != null)
|
|
{
|
|
int end = (int)endFile.getUintAt(endOffset);
|
|
if (endIsSize)
|
|
fileSize = (int)end;
|
|
else
|
|
fileSize = (int)end + parent.fileDataOffset - fileBegin;
|
|
}
|
|
}
|
|
|
|
public virtual void saveOffsets()
|
|
{
|
|
if (beginFile != null)
|
|
beginFile.setUintAt(beginOffset, (uint)(fileBegin - parent.fileDataOffset));
|
|
|
|
if (endFile != null)
|
|
if (endIsSize)
|
|
endFile.setUintAt(endOffset, (uint)fileSize);
|
|
else
|
|
endFile.setUintAt(endOffset, (uint)(fileBegin + fileSize - parent.fileDataOffset));
|
|
}
|
|
|
|
public uint getUintAt(int offset)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
|
|
|
|
uint res = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
res |= (uint)parent.s.ReadByte() << 8 * i;
|
|
}
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
return res;
|
|
}
|
|
|
|
public void setUintAt(int offset, uint val)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
parent.s.WriteByte((byte)(val & 0xFF));
|
|
val >>= 8;
|
|
}
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
}
|
|
|
|
public ushort getUshortAt(int offset)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
|
|
|
|
ushort res = 0;
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
res |= (ushort)(parent.s.ReadByte() << 8 * i);
|
|
}
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
return res;
|
|
}
|
|
|
|
|
|
public void setUshortAt(int offset, ushort val)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
parent.s.WriteByte((byte)(val & 0xFF));
|
|
val >>= 8;
|
|
}
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
}
|
|
|
|
public byte getByteAt(int offs)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offs, SeekOrigin.Begin);
|
|
byte res = (byte)parent.s.ReadByte();
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
return res;
|
|
}
|
|
|
|
public void setByteAt(int offs, byte val)
|
|
{
|
|
enableEdition();
|
|
long pos = parent.s.Position;
|
|
parent.s.Seek(fileBegin + offs, SeekOrigin.Begin);
|
|
parent.s.WriteByte(val);
|
|
parent.s.Seek(pos, SeekOrigin.Begin);
|
|
}
|
|
|
|
public bool isAGoodEditor(object editor)
|
|
{
|
|
if (!beingEdited)
|
|
return false;
|
|
|
|
if (editor == editedBy)
|
|
return true;
|
|
|
|
if (editor is InlineFile && inlineEditors.Contains(editor as InlineFile))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public virtual void replace(byte[] newFile, object editor)
|
|
{
|
|
//if (!isAGoodEditor(editor))
|
|
// throw new Exception("NOT CORRECT EDITOR " + name);
|
|
|
|
if (newFile.Length != fileSize && fixedFile)
|
|
throw new Exception("TRYING TO RESIZE FIXED FILE: " + name);
|
|
|
|
// enableEdition();
|
|
|
|
// Console.Out.WriteLine("Replacing: [" + id + "] " + name);
|
|
int newStart = fileBegin;
|
|
if (newFile.Length > fileSize) //if we insert a bigger file
|
|
{ //it might not fit in the current place
|
|
if (canChangeOffset)
|
|
{
|
|
newStart = parent.findFreeSpace(newFile.Length, alignment);
|
|
if (newStart % alignment != 0)
|
|
newStart += alignment - newStart % alignment;
|
|
}
|
|
else
|
|
{
|
|
parent.allFiles.Sort();
|
|
if (!(parent.allFiles.IndexOf(this) == parent.allFiles.Count - 1))
|
|
{
|
|
File nextFile = parent.allFiles[parent.allFiles.IndexOf(this) + 1];
|
|
parent.moveAllFiles(nextFile, fileBegin + newFile.Length);
|
|
}
|
|
}
|
|
}
|
|
/*else if (parent is NarcFilesystem)
|
|
{
|
|
parent.allFiles.Sort();
|
|
if (!(parent.allFiles.IndexOf(this) == parent.allFiles.Count - 1))
|
|
{
|
|
File nextFile = parent.allFiles[parent.allFiles.IndexOf(this) + 1];
|
|
parent.moveAllFiles(nextFile, fileBegin + newFile.Length);
|
|
}
|
|
}*/
|
|
if (newStart % alignment != 0)
|
|
Console.Out.Write("Warning: File is not being aligned: " + nameP + ", at " + newStart.ToString("X"));
|
|
//write the file
|
|
parent.s.Seek(newStart, SeekOrigin.Begin);
|
|
parent.s.Write(newFile, 0, newFile.Length);
|
|
//if (parent is NarcFilesystem)
|
|
// parent.s.SetLength(parent.allFiles[parent.allFiles.Count - 1].fileBegin + parent.allFiles[parent.allFiles.Count - 1].fileSize + 10);
|
|
//update ending pos
|
|
fileBegin = newStart;
|
|
fileSize = newFile.Length;
|
|
saveOffsets();
|
|
parent.fileMoved(this); //NEEDED FOR UPDATING TOTAL USED ROM SIZE IN HEADER
|
|
}
|
|
|
|
public void moveTo(int newOffs)
|
|
{
|
|
if (newOffs % alignment != 0)
|
|
Console.Out.Write("Warning: File is not being aligned: " + nameP + ", at " + newOffs.ToString("X"));
|
|
byte[] data = getContents();
|
|
parent.s.Seek(newOffs, SeekOrigin.Begin);
|
|
parent.s.Write(data, 0, data.Length);
|
|
fileBegin = newOffs;
|
|
saveOffsets();
|
|
}
|
|
|
|
public int CompareTo(object obj)
|
|
{
|
|
File f = obj as File;
|
|
if (fileBegin == f.fileBegin)
|
|
return fileSize.CompareTo(f.fileSize);
|
|
return fileBegin.CompareTo(f.fileBegin);
|
|
}
|
|
|
|
public virtual void beginEdit(Object editor)
|
|
{
|
|
if (beingEdited)
|
|
throw new Exception();
|
|
else
|
|
editedBy = editor;
|
|
}
|
|
|
|
public virtual void endEdit(Object editor)
|
|
{
|
|
//if (!beingEdited)
|
|
// throw new Exception("NOT EDITING FILE " + name);
|
|
//if (editor != editedBy)
|
|
// throw new Exception("NOT CORRECT EDITOR" + name);
|
|
|
|
editedBy = null;
|
|
}
|
|
|
|
public bool beingEditedBy(Object ed)
|
|
{
|
|
return ed == editedBy;
|
|
}
|
|
|
|
|
|
public bool isAddrInFile(int addr)
|
|
{
|
|
return addr >= fileBegin && addr < fileBegin + fileSize;
|
|
}
|
|
|
|
private List<InlineFile> inlineEditors = new List<InlineFile>();
|
|
|
|
public void beginEditInline(InlineFile f)
|
|
{
|
|
if (inlineEditors.Count == 0)
|
|
beginEdit(this);
|
|
|
|
inlineEditors.Add(f);
|
|
}
|
|
|
|
public void endEditInline(InlineFile f)
|
|
{
|
|
if (!inlineEditors.Contains(f))
|
|
throw new Exception("ERROR: INLINE FILE");
|
|
inlineEditors.Remove(f);
|
|
if (inlineEditors.Count == 0)
|
|
endEdit(this);
|
|
}
|
|
|
|
//Intended for compressed files like overlays.
|
|
//Must decompress the file so it's editable and still playable.
|
|
public virtual void enableEdition() { }
|
|
|
|
|
|
public string getPath()
|
|
{
|
|
return parentDir.getPath() + "/" + name;
|
|
}
|
|
}
|
|
}
|