2013-04-27 02:02:37 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2014-05-11 17:48:17 +00:00
using System.Linq ;
2013-04-27 02:02:37 +00:00
using System.Xml ;
2013-10-27 22:07:40 +00:00
using BizHawk.Common ;
2014-07-03 19:20:34 +00:00
using BizHawk.Common.BufferExtensions ;
2014-07-03 18:29:51 +00:00
using BizHawk.Common.IOExtensions ;
2013-11-04 01:06:36 +00:00
using BizHawk.Emulation.Common ;
2013-10-27 22:07:40 +00:00
2013-10-27 07:54:00 +00:00
namespace BizHawk.Client.Common
2013-04-27 02:02:37 +00:00
{
public class XmlGame
{
2014-01-08 03:53:53 +00:00
public XmlDocument Xml { get ; set ; }
2017-05-19 18:17:07 +00:00
public GameInfo GI { get ; } = new GameInfo ( ) ;
public IList < KeyValuePair < string , byte [ ] > > Assets { get ; } = new List < KeyValuePair < string , byte [ ] > > ( ) ;
public IList < string > AssetFullPaths { get ; } = new List < string > ( ) ; // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored!
2013-04-27 02:02:37 +00:00
2019-12-31 22:24:46 +00:00
/// <exception cref="InvalidOperationException">internal error</exception>
2013-04-27 02:02:37 +00:00
public static XmlGame Create ( HawkFile f )
{
try
{
var x = new XmlDocument ( ) ;
x . Load ( f . GetStream ( ) ) ;
var y = x . SelectSingleNode ( "./BizHawk-XMLGame" ) ;
if ( y = = null )
2014-01-08 03:53:53 +00:00
{
2013-04-27 02:02:37 +00:00
return null ;
2014-01-08 03:53:53 +00:00
}
2013-04-27 02:02:37 +00:00
2013-10-27 17:47:54 +00:00
var ret = new XmlGame
2017-04-14 19:59:01 +00:00
{
GI =
2013-10-27 17:47:54 +00:00
{
2017-04-14 19:59:01 +00:00
System = y . Attributes [ "System" ] . Value ,
Name = y . Attributes [ "Name" ] . Value ,
Status = RomStatus . Unknown
} ,
Xml = x
} ;
2019-11-15 21:15:13 +00:00
string fullPath = "" ;
2013-04-27 02:02:37 +00:00
var n = y . SelectSingleNode ( "./LoadAssets" ) ;
if ( n ! = null )
{
2017-05-19 18:17:07 +00:00
var hashStream = new MemoryStream ( ) ;
int? originalIndex = null ;
2013-04-27 17:43:15 +00:00
2013-04-27 02:02:37 +00:00
foreach ( XmlNode a in n . ChildNodes )
{
string filename = a . Attributes [ "FileName" ] . Value ;
2015-05-17 16:30:39 +00:00
byte [ ] data = new byte [ 0 ] ;
2013-04-27 02:02:37 +00:00
if ( filename [ 0 ] = = '|' )
{
// in same archive
var ai = f . FindArchiveMember ( filename . Substring ( 1 ) ) ;
if ( ai ! = null )
{
2017-05-19 18:17:07 +00:00
if ( originalIndex = = null )
2014-01-08 03:53:53 +00:00
{
2017-05-19 18:17:07 +00:00
originalIndex = f . GetBoundIndex ( ) ;
2014-01-08 03:53:53 +00:00
}
2013-04-27 17:24:23 +00:00
f . Unbind ( ) ;
2013-04-27 02:02:37 +00:00
f . BindArchiveMember ( ai ) ;
2014-07-03 18:29:51 +00:00
data = f . GetStream ( ) . ReadAllBytes ( ) ;
2013-04-27 02:02:37 +00:00
}
else
{
2019-03-20 05:01:12 +00:00
throw new Exception ( $"Couldn't load XMLGame Asset \" { filename } \ "" ) ;
2013-04-27 02:02:37 +00:00
}
}
else
{
// relative path
2019-11-15 21:15:13 +00:00
fullPath = Path . GetDirectoryName ( f . CanonicalFullPath . Split ( '|' ) . First ( ) ) ? ? "" ;
fullPath = Path . Combine ( fullPath , filename . Split ( '|' ) . First ( ) ) ;
2013-04-27 02:02:37 +00:00
try
{
2019-11-15 21:15:13 +00:00
using var hf = new HawkFile ( fullPath ) ;
if ( hf . IsArchive )
2015-05-17 16:30:39 +00:00
{
2019-11-15 21:15:13 +00:00
var archiveItem = hf . ArchiveItems . First ( ai = > ai . Name = = filename . Split ( '|' ) . Skip ( 1 ) . First ( ) ) ;
hf . Unbind ( ) ;
hf . BindArchiveMember ( archiveItem ) ;
data = hf . GetStream ( ) . ReadAllBytes ( ) ;
2018-08-16 14:58:48 +00:00
2019-11-15 21:15:13 +00:00
filename = filename . Split ( '|' ) . Skip ( 1 ) . First ( ) ;
}
else
{
data = File . ReadAllBytes ( fullPath . Split ( '|' ) . First ( ) ) ;
2015-05-17 16:30:39 +00:00
}
2013-04-27 02:02:37 +00:00
}
catch
{
2019-03-20 05:01:12 +00:00
throw new Exception ( $"Couldn't load XMLGame LoadAsset \" { filename } \ "" ) ;
2013-04-27 02:02:37 +00:00
}
}
2014-01-08 03:53:53 +00:00
2015-05-10 18:58:00 +00:00
ret . Assets . Add ( new KeyValuePair < string , byte [ ] > ( filename , data ) ) ;
2019-11-15 21:15:13 +00:00
ret . AssetFullPaths . Add ( fullPath ) ;
using var sha1 = System . Security . Cryptography . SHA1 . Create ( ) ;
sha1 . TransformFinalBlock ( data , 0 , data . Length ) ;
hashStream . Write ( sha1 . Hash , 0 , sha1 . Hash . Length ) ;
2013-04-27 02:02:37 +00:00
}
2014-01-08 03:53:53 +00:00
2017-05-19 18:17:07 +00:00
ret . GI . Hash = hashStream . GetBuffer ( ) . HashSHA1 ( 0 , ( int ) hashStream . Length ) ;
hashStream . Close ( ) ;
if ( originalIndex ! = null )
2013-04-27 17:43:15 +00:00
{
f . Unbind ( ) ;
2017-05-19 18:17:07 +00:00
f . BindArchiveMember ( ( int ) originalIndex ) ;
2013-04-27 17:43:15 +00:00
}
2013-04-27 15:51:31 +00:00
}
else
{
ret . GI . Hash = "0000000000000000000000000000000000000000" ;
2013-04-27 02:02:37 +00:00
}
2014-01-08 03:53:53 +00:00
2013-04-27 02:02:37 +00:00
return ret ;
}
2014-01-08 03:53:53 +00:00
catch ( Exception ex )
2013-04-27 02:02:37 +00:00
{
2013-10-27 07:54:00 +00:00
throw new InvalidOperationException ( ex . ToString ( ) ) ;
2013-04-27 02:02:37 +00:00
}
}
}
}