Skip to content

Commit

Permalink
Fixed parsing issue for spells/abilities when opened from different ROM
Browse files Browse the repository at this point in the history
  • Loading branch information
z16 committed Nov 9, 2017
1 parent 8b87c0e commit 71ec4d0
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 82 deletions.
5 changes: 4 additions & 1 deletion PlayOnline.FFXI.Utils.DataBrowser/FileScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ public void ScanFile(IWin32Window ParentForm, string FileName)
this.FSD.SetProgress(Message, PercentCompleted);
}));
}));
this.FSD.Invoke(new AnonymousMethod(delegate() { this.FSD.Finish(); }));
}
catch
{
this.FileContents = null;
}
finally
{
this.FSD.Invoke(new AnonymousMethod(delegate() { this.FSD.Finish(); }));
}
}));
T.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
T.Start();
Expand Down
222 changes: 141 additions & 81 deletions PlayOnline.FFXI/FileTypes/SpellAndAbilityInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,110 +9,170 @@

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
using PlayOnline.Core;

namespace PlayOnline.FFXI.FileTypes
{
public class SpellAndAbilityInfo : FileType
{
private enum BlockType
{
ContainerEnd = 0x00,
ContainerBegin = 0x01,
SpellData = 0x49,
AbilityData = 0x53,
}

[StructLayout(LayoutKind.Sequential)]
private struct Header
{
private int id;
private int size;
private long padding;

public int ID => id;
public int Size => (size >> 3 & ~0xF) - 0x10;
public BlockType Type => (BlockType) (size & 0x7F);
}

public static T Read<T>(Stream stream)
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback)
{
var size = Marshal.SizeOf(typeof(T));
var data = new byte[size];
stream.Read(data, 0, data.Length);

var ptr = IntPtr.Zero;
try
ThingList TL = new ThingList();
if (ProgressCallback != null)
{
ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0);
}
if (BR.BaseStream.Position != 0)
{
goto Failed;
}
if (Encoding.ASCII.GetString(BR.ReadBytes(4)) != "menu")
{
goto Failed;
}
if (BR.ReadInt32() != 0x101)
{
ptr = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, ptr, data.Length);
return (T)Marshal.PtrToStructure(ptr, typeof(T));
goto Failed;
}
finally
if (BR.ReadInt64() != 0)
{
if (ptr != IntPtr.Zero)
goto Failed;
}
if (BR.ReadInt64() != 0)
{
goto Failed;
}
if (BR.ReadInt64() != 0)
{
goto Failed;
}
if (ProgressCallback != null)
{
ProgressCallback(I18N.GetText("FTM:LoadingData"), (double)BR.BaseStream.Position / BR.BaseStream.Length);
}
string firstFourBytes = Encoding.ASCII.GetString(BR.ReadBytes(4));
{
// Part 0: Monster?
if (firstFourBytes != "mon_")
{
goto Part1;
}
uint SizeInfo = BR.ReadUInt32();
if (BR.ReadInt64() != 0)
{
goto Failed;
}
uint BlockSize = (SizeInfo & 0xFFFFFF80) >> 3;
if ((BlockSize - 0x10) % 0x58 != 0)
{
Marshal.FreeHGlobal(ptr);
goto Failed;
}
uint EntryCount = (BlockSize - 0x10) / 0x58;
while (EntryCount-- > 0)
{
Things.MonsterSpellInfo2 MSI2 = new Things.MonsterSpellInfo2();
if (!MSI2.Read(BR))
{
goto Failed;
}
if (ProgressCallback != null)
{
ProgressCallback(null, (double)BR.BaseStream.Position / BR.BaseStream.Length);
}
TL.Add(MSI2);
}
}
}

public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback)
{
var TL = new ThingList();
ProgressCallback?.Invoke(I18N.GetText("FTM:CheckingFile"), 0);

var stream = BR.BaseStream;

var header = Read<Header>(stream);
var block = stream.Position;

if (header.Type != BlockType.ContainerBegin)
firstFourBytes = Encoding.ASCII.GetString(BR.ReadBytes(4));
Part1:
{
throw new InvalidDataException();
// Part 1: Spell Info
if (firstFourBytes != "mgc_")
{
goto Failed;
}
uint SizeInfo = BR.ReadUInt32();
if (BR.ReadInt64() != 0)
{
goto Failed;
}
uint BlockSize = (SizeInfo & 0xFFFFFF80) >> 3;
if ((BlockSize - 0x10) % 0x58 != 0)
{
goto Failed;
}
uint EntryCount = (BlockSize - 0x10) / 0x58;
while (EntryCount-- > 0)
{
Things.SpellInfo2 SI2 = new Things.SpellInfo2();
if (!SI2.Read(BR))
{
goto Failed;
}
if (ProgressCallback != null)
{
ProgressCallback(null, (double)BR.BaseStream.Position / BR.BaseStream.Length);
}
TL.Add(SI2);
}
}

while (header.Type != BlockType.ContainerEnd)
{
stream.Position = block + header.Size;

header = Read<Header>(stream);
block = stream.Position;

switch (header.Type)
// Part 2: Ability Info
if (Encoding.ASCII.GetString(BR.ReadBytes(4)) != "comm")
{
goto Failed;
}
uint SizeInfo = BR.ReadUInt32();
if (BR.ReadInt64() != 0)
{
case BlockType.SpellData:
while (stream.Position < block + header.Size)
goto Failed;
}
uint BlockSize = (SizeInfo & 0xFFFFFF80) >> 3;
if ((BlockSize - 0x10) % 0x30 != 0)
{
goto Failed;
}
uint EntryCount = (BlockSize - 0x10) / 0x30;
while (EntryCount-- > 0)
{
Things.AbilityInfo2 AI2 = new Things.AbilityInfo2();
if (!AI2.Read(BR))
{
var SI2 = new Things.SpellInfo2();
if (!SI2.Read(BR))
{
TL.Clear();
return TL;
}
TL.Add(SI2);
goto Failed;
}
break;

case BlockType.AbilityData:
while (stream.Position < block + header.Size)
if (ProgressCallback != null)
{
var AI2 = new Things.AbilityInfo2();
if (!AI2.Read(BR))
{
TL.Clear();
return TL;
}
TL.Add(AI2);
ProgressCallback(null, (double)BR.BaseStream.Position / BR.BaseStream.Length);
}
break;

TL.Add(AI2);
}

ProgressCallback(I18N.GetText("FTM:LoadingData"), (double)BR.BaseStream.Position / BR.BaseStream.Length);
}

{
// Part 3: End Marker
if (Encoding.ASCII.GetString(BR.ReadBytes(4)) != "end\0")
{
goto Failed;
}
uint SizeInfo = BR.ReadUInt32();
if (BR.ReadInt64() != 0)
{
goto Failed;
}
uint BlockSize = (SizeInfo & 0xFFFFFF80) >> 3;
if (BlockSize != 0x10) // Header only
{
goto Failed;
}
if (ProgressCallback != null)
{
ProgressCallback(null, (double)BR.BaseStream.Position / BR.BaseStream.Length);
}
}
goto Done;
Failed:
TL.Clear();
Done:
return TL;
}
}
Expand Down

0 comments on commit 71ec4d0

Please sign in to comment.