2016-11-12 19:02:48 +03:00
using System ;
using System.IO ;
using System.Windows.Forms ;
2016-12-31 15:56:10 +03:00
using System.Text ;
2016-11-12 19:02:48 +03:00
using SonicAudioLib.CriMw ;
using SonicAudioLib.IO ;
using SonicAudioLib.Archive ;
namespace AcbEditor
{
class Program
{
static void Main ( string [ ] args )
{
if ( args . Length < 1 )
{
Console . WriteLine ( Properties . Resources . Description ) ;
Console . ReadLine ( ) ;
return ;
}
2016-12-31 15:56:10 +03:00
#if ! DEBUG
2016-11-12 19:02:48 +03:00
try
{
2016-12-31 15:56:10 +03:00
#endif
2016-11-12 19:02:48 +03:00
if ( args [ 0 ] . EndsWith ( ".acb" ) )
{
string baseDirectory = Path . GetDirectoryName ( args [ 0 ] ) ;
string outputDirectoryPath = Path . Combine ( baseDirectory , Path . GetFileNameWithoutExtension ( args [ 0 ] ) ) ;
string extAfs2ArchivePath = string . Empty ;
Directory . CreateDirectory ( outputDirectoryPath ) ;
using ( CriTableReader acbReader = CriTableReader . Create ( args [ 0 ] ) )
{
acbReader . Read ( ) ;
CriAfs2Archive afs2Archive = new CriAfs2Archive ( ) ;
CriAfs2Archive extAfs2Archive = new CriAfs2Archive ( ) ;
2016-12-31 15:56:10 +03:00
CriCpkArchive cpkArchive = new CriCpkArchive ( ) ;
CriCpkArchive extCpkArchive = null ;
extAfs2ArchivePath = outputDirectoryPath + ".awb" ;
bool found = File . Exists ( extAfs2ArchivePath ) ;
if ( ! found )
{
extAfs2ArchivePath = outputDirectoryPath + "_streamfiles.awb" ;
found = File . Exists ( extAfs2ArchivePath ) ;
}
if ( ! found )
{
extAfs2ArchivePath = outputDirectoryPath + "_STR.awb" ;
found = File . Exists ( extAfs2ArchivePath ) ;
}
bool cpkMode = true ;
2016-11-12 19:02:48 +03:00
if ( acbReader . GetLength ( "AwbFile" ) > 0 )
{
using ( Substream afs2Stream = acbReader . GetSubstream ( "AwbFile" ) )
{
2016-12-31 15:56:10 +03:00
cpkMode = ! CheckIfAfs2 ( afs2Stream ) ;
if ( cpkMode )
{
cpkArchive . Read ( afs2Stream ) ;
}
else
{
afs2Archive . Read ( afs2Stream ) ;
}
2016-11-12 19:02:48 +03:00
}
}
if ( acbReader . GetLength ( "StreamAwbAfs2Header" ) > 0 )
{
2016-12-31 15:56:10 +03:00
cpkMode = false ;
2016-11-12 19:02:48 +03:00
using ( Substream extAfs2Stream = acbReader . GetSubstream ( "StreamAwbAfs2Header" ) )
{
extAfs2Archive . Read ( extAfs2Stream ) ;
}
if ( ! found )
{
throw new Exception ( "Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is." ) ;
}
}
using ( Substream waveformTableStream = acbReader . GetSubstream ( "WaveformTable" ) )
using ( CriTableReader waveformReader = CriTableReader . Create ( waveformTableStream ) )
{
while ( waveformReader . Read ( ) )
{
2016-12-31 15:56:10 +03:00
ushort id = waveformReader . GetUInt16 ( "Id" ) ;
2016-11-12 19:02:48 +03:00
byte encodeType = waveformReader . GetByte ( "EncodeType" ) ;
bool streaming = waveformReader . GetBoolean ( "Streaming" ) ;
2016-12-31 15:56:10 +03:00
string outputName = id . ToString ( "D5" ) ;
2016-11-12 19:02:48 +03:00
if ( streaming )
{
outputName + = "_streaming" ;
}
outputName + = GetExtension ( encodeType ) ;
outputName = Path . Combine ( outputDirectoryPath , outputName ) ;
2016-12-31 15:56:10 +03:00
Console . WriteLine ( "Extracting {0} file with id {1}..." , GetExtension ( encodeType ) . ToUpper ( ) , id ) ;
2016-11-12 19:02:48 +03:00
if ( streaming )
{
2016-12-31 15:56:10 +03:00
if ( ! found )
{
throw new Exception ( "Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is." ) ;
}
else if ( extCpkArchive = = null & & cpkMode )
{
extCpkArchive = new CriCpkArchive ( ) ;
extCpkArchive . Load ( extAfs2ArchivePath ) ;
}
EntryBase afs2Entry = null ;
if ( cpkMode )
{
afs2Entry = extCpkArchive . GetById ( id ) ;
}
else
{
afs2Entry = extAfs2Archive . GetById ( id ) ;
}
2016-11-12 19:02:48 +03:00
using ( Stream extAfs2Stream = File . OpenRead ( extAfs2ArchivePath ) )
using ( Stream afs2EntryStream = afs2Entry . Open ( extAfs2Stream ) )
using ( Stream afs2EntryDestination = File . Create ( outputName ) )
{
afs2EntryStream . CopyTo ( afs2EntryDestination ) ;
}
}
else
{
2016-12-31 15:56:10 +03:00
EntryBase afs2Entry = null ;
if ( cpkMode )
{
afs2Entry = cpkArchive . GetById ( id ) ;
}
else
{
afs2Entry = afs2Archive . GetById ( id ) ;
}
2016-11-12 19:02:48 +03:00
using ( Substream afs2Stream = acbReader . GetSubstream ( "AwbFile" ) )
2016-12-31 15:56:10 +03:00
using ( Stream afs2EntryStream = afs2Entry . Open ( afs2Stream ) )
2016-11-12 19:02:48 +03:00
using ( Stream afs2EntryDestination = File . Create ( outputName ) )
{
afs2EntryStream . CopyTo ( afs2EntryDestination ) ;
}
}
}
}
}
}
else if ( File . GetAttributes ( args [ 0 ] ) . HasFlag ( FileAttributes . Directory ) )
{
string baseDirectory = Path . GetDirectoryName ( args [ 0 ] ) ;
string acbPath = args [ 0 ] + ".acb" ;
string awbPath = args [ 0 ] + "_streamfiles.awb" ;
bool found = File . Exists ( awbPath ) ;
if ( ! found )
{
awbPath = args [ 0 ] + "_STR.awb" ;
found = File . Exists ( awbPath ) ;
}
if ( ! found )
{
awbPath = args [ 0 ] + ".awb" ;
}
if ( ! File . Exists ( acbPath ) )
{
throw new Exception ( "Cannot find the .ACB file for this directory. Please ensure that the .ACB file is stored in the directory where this directory is." ) ;
}
CriTable acbFile = new CriTable ( ) ;
acbFile . Load ( acbPath ) ;
CriAfs2Archive afs2Archive = new CriAfs2Archive ( ) ;
CriAfs2Archive extAfs2Archive = new CriAfs2Archive ( ) ;
2016-12-31 15:56:10 +03:00
CriCpkArchive cpkArchive = new CriCpkArchive ( ) ;
CriCpkArchive extCpkArchive = new CriCpkArchive ( ) ;
cpkArchive . Mode = extCpkArchive . Mode = CriCpkMode . Id ;
bool cpkMode = true ;
byte [ ] awbFile = ( byte [ ] ) acbFile . Rows [ 0 ] [ "AwbFile" ] ;
byte [ ] streamAwbAfs2Header = ( byte [ ] ) acbFile . Rows [ 0 ] [ "StreamAwbAfs2Header" ] ;
cpkMode = ! ( awbFile ! = null & & awbFile . Length > = 4 & & Encoding . ASCII . GetString ( awbFile , 0 , 4 ) = = "AFS2" ) & & ( streamAwbAfs2Header = = null | | streamAwbAfs2Header . Length = = 0 ) ;
2016-11-12 19:02:48 +03:00
using ( CriTableReader reader = CriTableReader . Create ( ( byte [ ] ) acbFile . Rows [ 0 ] [ "WaveformTable" ] ) )
{
while ( reader . Read ( ) )
{
2016-12-31 15:56:10 +03:00
ushort id = reader . GetUInt16 ( "Id" ) ;
2016-11-12 19:02:48 +03:00
byte encodeType = reader . GetByte ( "EncodeType" ) ;
bool streaming = reader . GetBoolean ( "Streaming" ) ;
2016-12-31 15:56:10 +03:00
string inputName = id . ToString ( "D5" ) ;
2016-11-12 19:02:48 +03:00
if ( streaming )
{
inputName + = "_streaming" ;
}
inputName + = GetExtension ( encodeType ) ;
inputName = Path . Combine ( args [ 0 ] , inputName ) ;
if ( ! File . Exists ( inputName ) )
{
2016-12-31 15:56:10 +03:00
throw new Exception ( $"Cannot find audio file with id {id} for replacement.\nPath attempt: {inputName}" ) ;
2016-11-12 19:02:48 +03:00
}
Console . WriteLine ( "Adding {0}..." , Path . GetFileName ( inputName ) ) ;
2016-12-31 15:56:10 +03:00
if ( cpkMode )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
CriCpkEntry entry = new CriCpkEntry ( ) ;
entry . FilePath = new FileInfo ( inputName ) ;
entry . Id = id ;
if ( streaming )
{
extCpkArchive . Add ( entry ) ;
}
else
{
cpkArchive . Add ( entry ) ;
}
2016-11-12 19:02:48 +03:00
}
else
{
2016-12-31 15:56:10 +03:00
CriAfs2Entry entry = new CriAfs2Entry ( ) ;
entry . FilePath = new FileInfo ( inputName ) ;
entry . Id = id ;
if ( streaming )
{
extAfs2Archive . Add ( entry ) ;
}
else
{
afs2Archive . Add ( entry ) ;
}
2016-11-12 19:02:48 +03:00
}
}
}
acbFile . Rows [ 0 ] [ "AwbFile" ] = null ;
acbFile . Rows [ 0 ] [ "StreamAwbAfs2Header" ] = null ;
2016-12-31 15:56:10 +03:00
if ( afs2Archive . Count > 0 | | cpkArchive . Count > 0 )
2016-11-12 19:02:48 +03:00
{
Console . WriteLine ( "Saving internal AWB..." ) ;
2016-12-31 15:56:10 +03:00
acbFile . Rows [ 0 ] [ "AwbFile" ] = cpkMode ? cpkArchive . Save ( ) : afs2Archive . Save ( ) ;
2016-11-12 19:02:48 +03:00
}
2016-12-31 15:56:10 +03:00
if ( extAfs2Archive . Count > 0 | | extCpkArchive . Count > 0 )
2016-11-12 19:02:48 +03:00
{
Console . WriteLine ( "Saving external AWB..." ) ;
2016-12-31 15:56:10 +03:00
if ( cpkMode )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
extCpkArchive . Save ( awbPath ) ;
2016-11-12 19:02:48 +03:00
}
2016-12-31 15:56:10 +03:00
else
{
extAfs2Archive . Save ( awbPath ) ;
byte [ ] afs2Header = new byte [ 16 +
( extAfs2Archive . Count * extAfs2Archive . IdFieldLength ) +
( extAfs2Archive . Count * extAfs2Archive . PositionFieldLength ) +
extAfs2Archive . PositionFieldLength ] ;
using ( FileStream fileStream = File . OpenRead ( awbPath ) )
{
fileStream . Read ( afs2Header , 0 , afs2Header . Length ) ;
}
acbFile . Rows [ 0 ] [ "StreamAwbAfs2Header" ] = afs2Header ;
}
2016-11-12 19:02:48 +03:00
}
acbFile . WriterSettings = CriTableWriterSettings . Adx2Settings ;
acbFile . Save ( acbPath ) ;
}
2016-12-31 15:56:10 +03:00
#if ! DEBUG
2016-11-12 19:02:48 +03:00
}
catch ( Exception exception )
{
MessageBox . Show ( $"{exception.Message}" , "ACB Editor" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
}
2016-12-31 15:56:10 +03:00
#endif
2016-11-12 19:02:48 +03:00
}
static string GetExtension ( byte encodeType )
{
switch ( encodeType )
{
case 0 :
case 3 :
return ".adx" ;
case 1 :
return ".ahx" ;
case 2 :
return ".hca" ;
case 4 :
return ".wiiadpcm" ;
case 5 :
return ".dsadpcm" ;
case 6 :
return ".hcamx" ;
case 10 :
case 7 :
return ".vag" ;
case 8 :
return ".at3" ;
case 9 :
2016-12-31 15:56:10 +03:00
return ".bcwav" ;
2016-11-12 19:02:48 +03:00
case 18 :
case 11 :
return ".at9" ;
case 12 :
return ".xma" ;
case 13 :
2016-12-31 15:56:10 +03:00
return ".dsp" ;
2016-11-12 19:02:48 +03:00
default :
return ".bin" ;
}
}
2016-12-31 15:56:10 +03:00
static bool CheckIfAfs2 ( Stream source )
{
long oldPosition = source . Position ;
bool result = false ;
result = EndianStream . ReadCString ( source , 4 ) = = "AFS2" ;
source . Seek ( oldPosition , SeekOrigin . Begin ) ;
return result ;
}
2016-11-12 19:02:48 +03:00
}
}