mirror of
https://github.com/ficed/Braver.git
synced 2024-12-04 03:02:37 +00:00
7ad0855f8b
-add battle model export, move some GLTF export code into ancestor class -add option to swap triangle winding
106 lines
4.0 KiB
C#
106 lines
4.0 KiB
C#
// This program and the accompanying materials are made available under the terms of the
|
|
// Eclipse Public License v2.0 which accompanies this distribution, and is available at
|
|
// https://www.eclipse.org/legal/epl-v20.html
|
|
//
|
|
// SPDX-License-Identifier: EPL-2.0
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Ficedula.FF7 {
|
|
public class LGPFile : IDisposable {
|
|
|
|
private class Entry {
|
|
public int Offset { get; init; }
|
|
public string Name { get; init; }
|
|
public bool ExtendedName { get; init; }
|
|
public string? Path { get; set; }
|
|
|
|
public string FullPath {
|
|
get {
|
|
if (Path == null)
|
|
return Name;
|
|
else
|
|
return Path + "/" + Name;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Stream _source;
|
|
private Dictionary<string, Entry> _entries;
|
|
|
|
public IEnumerable<string> Filenames => _entries.Select(e => e.Value.FullPath);
|
|
|
|
public LGPFile(string filename) : this(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
|
}
|
|
|
|
public LGPFile(Stream source) {
|
|
_source = source;
|
|
_source.Position = 0;
|
|
if (_source.ReadI16() != 0)
|
|
throw new FFException("Invalid LGP file: bad header(0)");
|
|
if (!_source.ReadAscii(10).Equals("SQUARESOFT"))
|
|
throw new FFException("Invalid LGP file: bad header(1)");
|
|
|
|
int numFiles = _source.ReadI32();
|
|
List<Entry> tempEntries = new List<Entry>();
|
|
foreach (int i in Enumerable.Range(0, numFiles)) {
|
|
string name = _source.ReadAscii(20).Trim('\0', ' ');
|
|
int offset = _source.ReadI32();
|
|
_source.ReadByte();
|
|
bool extended = _source.ReadI16() != 0;
|
|
tempEntries.Add(new Entry {
|
|
Name = name,
|
|
Offset = offset,
|
|
ExtendedName = extended,
|
|
});
|
|
}
|
|
if (tempEntries.Any(e => e.ExtendedName)) {
|
|
_source.Seek(3600, System.IO.SeekOrigin.Current);
|
|
foreach (int _ in Enumerable.Range(0, _source.ReadI16())) {
|
|
foreach (int __ in Enumerable.Range(0, _source.ReadI16())) {
|
|
string path = _source.ReadAscii(128);
|
|
int nullIndex = path.IndexOf('\0');
|
|
if (nullIndex >= 0)
|
|
path = path.Substring(0, nullIndex);
|
|
int entry = _source.ReadI16();
|
|
tempEntries[entry].Path = path.Trim('\0');
|
|
}
|
|
}
|
|
}
|
|
_entries = tempEntries
|
|
.ToDictionary(e => e.FullPath, e => e, StringComparer.InvariantCultureIgnoreCase);
|
|
}
|
|
|
|
public bool Exists(string name) => _entries.ContainsKey(name);
|
|
|
|
public Stream? TryOpen(string name) {
|
|
if (_entries.TryGetValue(name, out Entry? e)) {
|
|
_source.Position = e.Offset + 20;
|
|
int length = _source.ReadI32();
|
|
//TODO: don't always load into memory, support passthrough reading from source?
|
|
byte[] buffer = new byte[length];
|
|
_source.Read(buffer, 0, length);
|
|
var mem = new MemoryStream(buffer);
|
|
return mem;
|
|
} else
|
|
return null;
|
|
}
|
|
public Stream Open(string name) {
|
|
var s = TryOpen(name);
|
|
if (s == null)
|
|
throw new FFException($"LGP file {name} not found");
|
|
return s;
|
|
}
|
|
|
|
public void Dispose() {
|
|
_source.Dispose();
|
|
}
|
|
|
|
public override string ToString() => $"LGP {_source}";
|
|
}
|
|
}
|