(PAZ): support older archives format.

This commit is contained in:
morkt 2017-01-09 14:54:56 +04:00
parent a14c781ae3
commit 98a424a521
3 changed files with 53 additions and 20 deletions

View File

@ -100,6 +100,7 @@
<Compile Include="Cmvs\ImageMSK.cs" /> <Compile Include="Cmvs\ImageMSK.cs" />
<Compile Include="Cmvs\ImagePB2.cs" /> <Compile Include="Cmvs\ImagePB2.cs" />
<Compile Include="Ellefin\ArcEPK.cs" /> <Compile Include="Ellefin\ArcEPK.cs" />
<Compile Include="Entis\ArcPAC.cs" />
<Compile Include="Majiro\ImageRC8.cs" /> <Compile Include="Majiro\ImageRC8.cs" />
<Compile Include="NSystem\ArcFJSYS.cs" /> <Compile Include="NSystem\ArcFJSYS.cs" />
<Compile Include="NSystem\ImageMGD.cs" /> <Compile Include="NSystem\ImageMGD.cs" />

View File

@ -129,13 +129,17 @@ namespace GameRes.Formats.Musica
if (!file.Name.EndsWith (".paz", StringComparison.InvariantCultureIgnoreCase)) if (!file.Name.EndsWith (".paz", StringComparison.InvariantCultureIgnoreCase))
return null; return null;
uint signature = file.View.ReadUInt32 (0); uint signature = file.View.ReadUInt32 (0);
uint index_size = file.View.ReadUInt32 (0x20);
byte xor_key = (byte)(index_size >> 24);
index_size ^= (uint)(xor_key << 24 | xor_key << 16 | xor_key << 8 | xor_key);
if (index_size + 0x24 >= file.MaxOffset)
return null;
var arc_name = Path.GetFileNameWithoutExtension (file.Name).ToLowerInvariant(); var arc_name = Path.GetFileNameWithoutExtension (file.Name).ToLowerInvariant();
// XXX encryption is queried for every .paz file
var scheme = QueryEncryption (arc_name, signature); var scheme = QueryEncryption (arc_name, signature);
uint start_offset = scheme.Version > 0 ? 0x20u : 0u;
uint index_size = file.View.ReadUInt32 (start_offset);
start_offset += 4;
byte xor_key = (byte)(index_size >> 24);
if (xor_key != 0)
index_size ^= (uint)(xor_key << 24 | xor_key << 16 | xor_key << 8 | xor_key);
if (0 != (index_size & 7) || index_size + start_offset >= file.MaxOffset)
return null;
var arc_list = new List<Entry>(); var arc_list = new List<Entry>();
var arc_dir = VFS.GetDirectoryName (file.Name); var arc_dir = VFS.GetDirectoryName (file.Name);
@ -151,11 +155,12 @@ namespace GameRes.Formats.Musica
} }
bool is_audio = AudioPazNames.Contains (arc_name); bool is_audio = AudioPazNames.Contains (arc_name);
bool is_video = VideoPazNames.Contains (arc_name); bool is_video = VideoPazNames.Contains (arc_name);
Stream input = file.CreateStream (0x24, index_size); Stream input = file.CreateStream (start_offset, index_size);
byte[] video_key = null; byte[] video_key = null;
List<Entry> dir; List<Entry> dir;
try try
{ {
if (xor_key != 0)
input = new XoredStream (input, xor_key); input = new XoredStream (input, xor_key);
var enc = new Blowfish (scheme.ArcKeys[arc_name].IndexKey); var enc = new Blowfish (scheme.ArcKeys[arc_name].IndexKey);
input = new InputCryptoStream (input, enc.CreateDecryptor()); input = new InputCryptoStream (input, enc.CreateDecryptor());
@ -173,16 +178,18 @@ namespace GameRes.Formats.Musica
var name = index.BaseStream.ReadCString(); var name = index.BaseStream.ReadCString();
var entry = FormatCatalog.Instance.Create<PazEntry> (name); var entry = FormatCatalog.Instance.Create<PazEntry> (name);
entry.Offset = index.ReadInt64(); entry.Offset = index.ReadInt64();
entry.UnpackedSize = index.ReadUInt32();
entry.Size = index.ReadUInt32(); entry.Size = index.ReadUInt32();
entry.AlignedSize = index.ReadUInt32();
if (!entry.CheckPlacement (max_offset)) if (!entry.CheckPlacement (max_offset))
return null; return null;
entry.UnpackedSize = index.ReadUInt32(); entry.IsPacked = index.ReadInt32 () != 0;
entry.AlignedSize = index.ReadUInt32();
entry.IsPacked = index.ReadInt32() != 0;
if (string.IsNullOrEmpty (entry.Type) && is_audio) if (string.IsNullOrEmpty (entry.Type) && is_audio)
{ {
entry.Type = "audio"; entry.Type = "audio";
} }
if (scheme.Version > 0)
{
string password = ""; string password = "";
if (!entry.IsPacked && scheme.TypeKeys != null) if (!entry.IsPacked && scheme.TypeKeys != null)
{ {
@ -193,6 +200,7 @@ namespace GameRes.Formats.Musica
password = string.Format ("{0} {1:X08} {2}", name.ToLowerInvariant(), entry.UnpackedSize, password); password = string.Format ("{0} {1:X08} {2}", name.ToLowerInvariant(), entry.UnpackedSize, password);
entry.Key = Encodings.cp932.GetBytes (password); entry.Key = Encodings.cp932.GetBytes (password);
} }
}
dir.Add (entry); dir.Add (entry);
} }
} }
@ -221,7 +229,16 @@ namespace GameRes.Formats.Musica
} }
} }
if (is_video) if (is_video)
{
if (scheme.Version < 1)
{
var table = new byte[0x100];
for (int i = 0; i < 0x100; ++i)
table[video_key[i]] = (byte)i;
video_key = table;
}
return new MovPazArchive (file, this, dir, scheme.Version, xor_key, video_key, parts); return new MovPazArchive (file, this, dir, scheme.Version, xor_key, video_key, parts);
}
return new PazArchive (file, this, dir, scheme.Version, xor_key, scheme.ArcKeys[arc_name].DataKey, parts); return new PazArchive (file, this, dir, scheme.Version, xor_key, scheme.ArcKeys[arc_name].DataKey, parts);
} }
@ -258,6 +275,7 @@ namespace GameRes.Formats.Musica
if (null == input) if (null == input)
return Stream.Null; return Stream.Null;
if (parc.XorKey != 0)
input = new XoredStream (input, parc.XorKey); input = new XoredStream (input, parc.XorKey);
if (parc is MovPazArchive) if (parc is MovPazArchive)
input = DecryptVideo (input, (MovPazArchive)parc, pent); input = DecryptVideo (input, (MovPazArchive)parc, pent);
@ -280,6 +298,17 @@ namespace GameRes.Formats.Musica
Stream DecryptVideo (Stream input, MovPazArchive arc, PazEntry entry) Stream DecryptVideo (Stream input, MovPazArchive arc, PazEntry entry)
{ {
if (arc.Version < 1)
{
using (input)
{
var data = new byte[entry.AlignedSize];
input.Read (data, 0, data.Length);
for (int i = 0; i < data.Length; ++i)
data[i] = arc.MovKey[data[i]];
return new BinMemoryStream (data, entry.Name);
}
}
var key = new byte[0x100]; var key = new byte[0x100];
for (int i = 0; i < 0x100; ++i) for (int i = 0; i < 0x100; ++i)
key[i] = (byte)(arc.MovKey[i] ^ entry.Key[i % entry.Key.Length]); key[i] = (byte)(arc.MovKey[i] ^ entry.Key[i % entry.Key.Length]);

View File

@ -131,6 +131,7 @@ Happy Princess<br/>
Happy Princess ~Another Fairytale~<br/> Happy Princess ~Another Fairytale~<br/>
Idol ☆ Revolution<br/> Idol ☆ Revolution<br/>
Katahane<br/> Katahane<br/>
Magical Kanon 2 ~Hiiro no Bergamot~<br/>
Narimono<br/> Narimono<br/>
Reconquista<br/> Reconquista<br/>
Switch!! ~Boku ga Natsu ni Omou Koto~<br/> Switch!! ~Boku ga Natsu ni Omou Koto~<br/>
@ -1251,6 +1252,7 @@ Tiara<br/>
</td></tr> </td></tr>
<tr class="odd last"><td>*.gbc</td><td><tt>GBCF</tt></td><td>No</td></tr> <tr class="odd last"><td>*.gbc</td><td><tt>GBCF</tt></td><td>No</td></tr>
<tr><td>*.paz</td><td>-</td><td>No</td><td>Musica</td><td> <tr><td>*.paz</td><td>-</td><td>No</td><td>Musica</td><td>
Haru no Ashioto<br/>
Tsumi no Hikari Rendezvous<br/> Tsumi no Hikari Rendezvous<br/>
</td></tr> </td></tr>
<tr class="odd"><td>arc.dat</td><td>-</td><td>No</td><td rowspan="2">AdvSys3</td><td rowspan="2"> <tr class="odd"><td>arc.dat</td><td>-</td><td>No</td><td rowspan="2">AdvSys3</td><td rowspan="2">
@ -1305,6 +1307,7 @@ Tsumadori
</td></tr> </td></tr>
<tr><td>*.epk</td><td><tt>EPK</tt></td><td>No</td><td rowspan="2">Ellefin Game System</td><td rowspan="2"> <tr><td>*.epk</td><td><tt>EPK</tt></td><td>No</td><td rowspan="2">Ellefin Game System</td><td rowspan="2">
Angelium -Tokimeki Love God-<br/> Angelium -Tokimeki Love God-<br/>
Teri ☆ Mix<br/>
</td></tr> </td></tr>
<tr class="last"><td>*.elg</td><td><tt>ELG</tt></td><td>No</td></tr> <tr class="last"><td>*.elg</td><td><tt>ELG</tt></td><td>No</td></tr>
</table> </table>