mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-25 20:34:13 +08:00
(VFF): recognize multi-part archives.
This commit is contained in:
parent
111481c4ac
commit
48d741c37c
@ -2,7 +2,7 @@
|
|||||||
//! \date Wed Jun 08 00:27:36 2016
|
//! \date Wed Jun 08 00:27:36 2016
|
||||||
//! \brief LiveMaker resource archive.
|
//! \brief LiveMaker resource archive.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2016 by morkt
|
// Copyright (C) 2016-2018 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@ -51,13 +51,14 @@ namespace GameRes.Formats.LiveMaker
|
|||||||
{
|
{
|
||||||
uint base_offset = 0;
|
uint base_offset = 0;
|
||||||
ArcView index_file = file;
|
ArcView index_file = file;
|
||||||
ArcView extra_file = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// possible filesystem structure:
|
// possible filesystem structure:
|
||||||
// game.dat -- main archive body
|
// game.dat -- main archive body
|
||||||
// game.001 -- [optional] extra part
|
|
||||||
// game.ext -- [optional] separate index (could be included into the main body)
|
// game.ext -- [optional] separate index (could be included into the main body)
|
||||||
|
// game.001 -- [optional] extra parts
|
||||||
|
// game.002
|
||||||
|
// ...
|
||||||
|
|
||||||
uint signature = index_file.View.ReadUInt32 (0);
|
uint signature = index_file.View.ReadUInt32 (0);
|
||||||
if (file.Name.HasExtension (".exe")
|
if (file.Name.HasExtension (".exe")
|
||||||
@ -88,37 +89,30 @@ namespace GameRes.Formats.LiveMaker
|
|||||||
if (null == dir)
|
if (null == dir)
|
||||||
return null;
|
return null;
|
||||||
long max_offset = file.MaxOffset;
|
long max_offset = file.MaxOffset;
|
||||||
for (int i = 0; i < dir.Count; ++i)
|
var parts = new List<ArcView>();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!dir[i].CheckPlacement (max_offset))
|
for (int i = 1; i < 100; ++i)
|
||||||
{
|
{
|
||||||
if (extra_file != null)
|
var ext = string.Format (".{0:D3}", i);
|
||||||
{
|
var part_filename = Path.ChangeExtension (file.Name, ext);
|
||||||
// remove entries that don't fit into game.dat+game.001
|
if (!VFS.FileExists (part_filename))
|
||||||
int discard = dir.Count - i;
|
|
||||||
Trace.WriteLine (string.Format ("{0} entries didn't fit and were discarded", discard), "[vff]");
|
|
||||||
dir.RemoveRange (i, discard);
|
|
||||||
break;
|
break;
|
||||||
|
var arc_file = VFS.OpenView (part_filename);
|
||||||
|
max_offset += arc_file.MaxOffset;
|
||||||
|
parts.Add (arc_file);
|
||||||
}
|
}
|
||||||
var extra_filename = Path.ChangeExtension (file.Name, ".001");
|
|
||||||
if (!VFS.FileExists (extra_filename))
|
|
||||||
return null;
|
|
||||||
extra_file = VFS.OpenView (extra_filename);
|
|
||||||
max_offset += extra_file.MaxOffset;
|
|
||||||
if (!dir[i].CheckPlacement (max_offset))
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (null == extra_file)
|
|
||||||
return new ArcFile (file, this, dir);
|
|
||||||
return new VffArchive (file, this, dir, extra_file);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
if (extra_file != null)
|
foreach (var part in parts)
|
||||||
extra_file.Dispose();
|
part.Dispose();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
if (0 == parts.Count)
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
return new MultiFileArchive (file, this, dir, parts);
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (index_file != file)
|
if (index_file != file)
|
||||||
@ -128,7 +122,7 @@ namespace GameRes.Formats.LiveMaker
|
|||||||
|
|
||||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
{
|
{
|
||||||
var vff = arc as VffArchive;
|
var vff = arc as MultiFileArchive;
|
||||||
Stream input = null;
|
Stream input = null;
|
||||||
if (vff != null)
|
if (vff != null)
|
||||||
input = vff.OpenStream (entry);
|
input = vff.OpenStream (entry);
|
||||||
@ -218,43 +212,4 @@ namespace GameRes.Formats.LiveMaker
|
|||||||
m_current = 0;
|
m_current = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class VffArchive : ArcFile
|
|
||||||
{
|
|
||||||
readonly ArcView ExtraFile;
|
|
||||||
|
|
||||||
public VffArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, ArcView extra_file)
|
|
||||||
: base (arc, impl, dir)
|
|
||||||
{
|
|
||||||
ExtraFile = extra_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Stream OpenStream (Entry entry)
|
|
||||||
{
|
|
||||||
if (entry.Offset < File.MaxOffset && entry.Offset+entry.Size > File.MaxOffset)
|
|
||||||
{
|
|
||||||
var first_part = File.View.ReadBytes (entry.Offset, entry.Size);
|
|
||||||
var second_part = ExtraFile.CreateStream (0, entry.Size - (uint)first_part.Length);
|
|
||||||
return new PrefixStream (first_part, second_part);
|
|
||||||
}
|
|
||||||
else if (entry.Offset >= File.MaxOffset)
|
|
||||||
{
|
|
||||||
return ExtraFile.CreateStream (entry.Offset, entry.Size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return File.CreateStream (entry.Offset, entry.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _vff_disposed = false;
|
|
||||||
protected override void Dispose (bool disposing)
|
|
||||||
{
|
|
||||||
if (!_vff_disposed)
|
|
||||||
{
|
|
||||||
if (disposing && ExtraFile != null)
|
|
||||||
ExtraFile.Dispose();
|
|
||||||
_vff_disposed = true;
|
|
||||||
}
|
|
||||||
base.Dispose (disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user