using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace OpenVIII
{
///
/// Loads strings from FF8 files
///
public partial class Strings
{
#region Classes
public abstract class StringsBase
{
#region Fields
protected Memory.Archive Archive;
protected string[] Filenames;
protected StringFile Files;
protected FF8StringReference.Settings Settings;
#endregion Fields
#region Constructors
protected StringsBase()
{
}
protected void SetValues(Memory.Archive archive, params string[] filenames)
{
Debug.WriteLine("Task={0}, Thread={2}, [Files={1}]",
Task.CurrentId, string.Join(", ", filenames),
Thread.CurrentThread.ManagedThreadId);
Archive = archive;
Filenames = filenames;
}
#endregion Constructors
#region Indexers
public FF8StringReference this[uint sectionid, int stringid] => Files[sectionid, stringid];
#endregion Indexers
#region Methods
public Memory.Archive GetArchive() => Archive;
public IReadOnlyList GetFilenames() => Filenames;
public StringFile GetFiles() => Files;
///
///
/// So you read the pointers at location, you get so many pointers then skip so many
/// bytes before getting more pointers. Do this till start of next section.
///
///
/// BinaryReader where data is.
/// file you are reading from
/// Section where pointers are.
/// Section where strings are
/// Get so many pointers
/// Then skip so many bytes
protected void Get_Strings_BinMSG(BinaryReader br, string filename, uint PointerStart, uint StringStart, uint grab = 0, uint skip = 0)
{
Loc fpos = Files.subPositions[(int)PointerStart];
br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
if (Files.sPositions.ContainsKey(PointerStart))
{
}
else
{
ushort b = 0;
ushort last = b;
if (!Files.sPositions.ContainsKey(PointerStart))
{
Files.sPositions.Add(PointerStart, new List());
uint g = 1;
while (br.BaseStream.Position < fpos.max)
{
b = br.ReadUInt16();
if (last > b)
break;
else
{
if (b != 0xFFFF)
{
Files.sPositions[PointerStart].Add(new FF8StringReference(Archive, filename, b + StringStart, settings: Settings));
last = b;
}
else
Files.sPositions[PointerStart].Add(null);
if (grab > 0 && ++g > grab)
{
br.BaseStream.Seek(skip, SeekOrigin.Current);
g = 1;
}
}
}
}
}
}
protected void Get_Strings_ComplexStr(BinaryReader br, string filename, uint key, List list)
{
uint[] fPaddings;
fPaddings = mngrp_read_padding(br, Files.subPositions[(int)key], 1);
Files.sPositions.Add(key, new List());
for (uint p = 0; p < fPaddings.Length; p += 2)
{
key = list[(int)fPaddings[(int)p + 1]];
Loc fpos = Files.subPositions[(int)key];
uint fpad = fPaddings[p] + fpos.seek;
br.BaseStream.Seek(fpad, SeekOrigin.Begin);
if (!Files.sPositions.ContainsKey(key))
Files.sPositions.Add(key, new List());
br.BaseStream.Seek(fpad + 6, SeekOrigin.Begin);
//byte[] UNK = br.ReadBytes(6);
ushort len = br.ReadUInt16();
uint stop = (uint)(br.BaseStream.Position + len - 9); //6 for UNK, 2 for len 1, for end null
Files.sPositions[key].Add(new FF8StringReference(Archive, filename, (uint)br.BaseStream.Position, settings: Settings));
//entry contains possible more than one string so I am scanning for null
while (br.BaseStream.Position + 1 < stop)
{
byte b = br.ReadByte();
if (b == 0) Files.sPositions[key].Add(new FF8StringReference(Archive, filename, (uint)br.BaseStream.Position, settings: Settings));
}
}
}
///
/// TODO: make this work with more than one file.
///
///
///
///
///
protected void Get_Strings_Offsets(BinaryReader br, string filename, uint key, bool pad = false)
{
Loc fpos = Files.subPositions[(int)key];
uint[] fPaddings = pad ? mngrp_read_padding(br, fpos) : (new uint[] { 1 });
Files.sPositions.Add(key, new List());
for (uint p = 0; p < fPaddings.Length; p++)
{
if (fPaddings[p] <= 0) continue;
uint fpad = pad ? fPaddings[p] + fpos.seek : fpos.seek;
br.BaseStream.Seek(fpad, SeekOrigin.Begin);
if (br.BaseStream.Position + 4 < br.BaseStream.Length)
{
int count = br.ReadUInt16();
for (int i = 0; i < count && br.BaseStream.Position + 2 < br.BaseStream.Length; i++)
{
uint c = br.ReadUInt16();
if (c < br.BaseStream.Length && c != 0)
{
c += fpad;
Files.sPositions[key].Add(new FF8StringReference(Archive, filename, c, settings: Settings));
}
}
}
}
}
protected abstract void GetFileLocations(BinaryReader br);
protected abstract void LoadArchiveFiles();
protected uint[] mngrp_read_padding(BinaryReader br, Loc fpos, int type = 0)
{
uint[] fPaddings = null;
br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
uint size = type == 0 ? br.ReadUInt16() : br.ReadUInt32();
fPaddings = new uint[type == 0 ? size : size * type * 2];
for (int i = 0; i < fPaddings.Length; i += 1 + type)
{
fPaddings[i] = br.ReadUInt16();
if (type == 0 && fPaddings[i] + fpos.seek >= fpos.max)
fPaddings[i] = 0;
//if (fPaddings[i] != 0)
// fPaddings[i] += fpos.seek;
for (int j = 1; j < type + 1; j++)
{
fPaddings[i + j] = br.ReadUInt16();
}
}
return fPaddings;
}
protected abstract void DefaultValues();
static public T Load() where T : StringsBase,new()
{
T r = new T();
r.DefaultValues();
r.LoadArchiveFiles();
return r;
}
protected void LoadArchiveFiles_Simple()
{
ArchiveWorker aw = new ArchiveWorker(Archive, true);
MemoryStream ms;
using (BinaryReader br = new BinaryReader(ms = new MemoryStream(aw.GetBinaryFile(Filenames[0], true))))
{
Files = new StringFile(1);
Files.subPositions.Add(new Loc { seek = 0, length = uint.MaxValue });
Get_Strings_Offsets(br, Filenames[0], 0);
ms = null;
}
}
}
#endregion Methods
}
#endregion Classes
}